//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////


#include "precomp.h"

#define OPLIST_COPS     1
#define OPLIST_SOPS     2

RILSUBSCRIBERINFO g_rsi[8];
DWORD g_rsiused = 0;
extern BOOL g_fReportLocationUpdateAsRegistrationState;
extern BOOL g_bRadioOff;
UINT g_iLastCOPS = 0;
UINT g_iSetCOPSinInit = NO_INIT_COPS_SETTING;
char g_szSetCOPSinInitOperator[MAXLENGTH_OPERATOR_NUMERIC+1];

UINT g_iPPLMNBufferPos = PPLMN_BUFFER_NOT_FILLED;
UINT g_PPLMNBuffer[MAX_PPLMN_BUFFER];
CRITICAL_SECTION g_PPLMNBufferSection;

#ifdef RIL_USE_CSQ_NOTIFICATIONS
extern BOOL g_bCINDIsActive;
DWORD WINAPI ReSendSignalThreadProc(LPVOID pVoid);
#endif

// Use this define to use the original Microsoft provider list
// rather than the latest Siemens List
#define USE_MICROSOFT_PROVIDER_LIST

#ifdef X86_EMUL
//
// Long operator names
//
static const OPERATORNAMEMAP g_rgonmOperatorNames[] =
{
#ifdef USE_MICROSOFT_PROVIDER_LIST
    { 20201,    "Cosmote" },
    { 20205,    "Vodafone GR" },
    { 20210,    "TELESTET" },
    { 20404,    "Vodafone NL" },
    { 20408,    "KPN" },
    { 20412,    "O2 - NL" },
    { 20416,    "Ben" },
    { 20420,    "dutchtone" },
    { 20601,    "Proximus" },
    { 20610,    "Mobistar" },
    { 20620,    "Orange" },
    { 20801,    "Orange" },
    { 20810,    "SFR" },
    { 20820,    "BOUYGTEL" },
    { 21303,    "Mobiland" },
    { 21401,    "Vodafone E" },
    { 21402,    "MoviStar" },
    { 21403,    "AMENA" },
    { 21404,    "Xfera" },
    { 21407,    "MoviStar" },
    { 21601,    "Pannon GSM" },
    { 21630,    "Westel" },
    { 21670,    "Vodafone" },
    { 21803,    "ERONET" },
    { 21805,    "Mobilna Srpska" },
    { 21890,    "GSM BiH" },
    { 21901,    "CRONET" },
    { 21910,    "VIP" },
    { 22001,    "MOBTEL" },
    { 22002,    "ProMonte" },
    { 22003,    "Telekom Srbija" },
    { 22004,    "MONET" },
    { 22201,    "TIM" },
    { 22210,    "Vodafone IT" },
    { 22288,    "WIND" },
    { 22298,    "Blu SpA" },
    { 22601,    "CONNEX" },
    { 22603,    "Cosmorom" },
    { 22610,    "dialog" },
    { 22801,    "Swiss GSM" },
    { 22802,    "sunrise" },
    { 22803,    "Orange" },
    { 23001,    "PAEGAS" },
    { 23002,    "EUROTEL" },
    { 23003,    "OSKAR" },
    { 23101,    "GLOBTEL" },
    { 23102,    "EUROTEL" },
    { 23201,    "A1" },
    { 23203,    "T-Mobile" },
    { 23205,    "ONE" },
    { 23207,    "tele.ring" },
    { 23410,    "O2 - UK" },
    { 23415,    "Vodafone" },
    { 23430,    "T-Mobile UK" },
    { 23431,    "T-Mobile UK" },
    { 23432,    "T-Mobile UK" },
    { 23433,    "Orange" },
    { 23450,    "JT GSM" },
    { 23455,    "GUERNSEY TEL" },
    { 23458,    "MANX" },
    { 23801,    "TDK-MOBIL" },
    { 23802,    "SONOFON" },
    { 23820,    "Telia" },
    { 23830,    "Orange" },
    { 24001,    "Telia S" },
    { 24007,    "IQ" },
    { 24008,    "Vodafone" },
    { 24201,    "TELENOR" },
    { 24202,    "NetCom" },
    { 24403,    "Telia" },
    { 24405,    "RADIOLINJA" },
    { 24409,    "FINNET" },
    { 24412,    "2G" },
    { 24414,    "AMT" },
    { 24491,    "SONERA" },
    { 24601,    "OMNITEL" },
    { 24602,    "Bite GSM" },
    { 24603,    "TELE2" },
    { 24701,    "LMT GSM" },
    { 24702,    "BALTCOM" },
    { 24801,    "EMT GSM" },
    { 24802,    "RLE" },
    { 24803,    "Q GSM" },
    { 25001,    "MTS" },
    { 25002,    "NorthWest GSM" },
    { 25003,    "NCC" },
    { 25005,    "SCS" },
    { 25007,    "SMARTS" },
    { 25010,    "DTC" },
    { 25011,    "Orensot" },
    { 25012,    "Far East" },
    { 25013,    "Kuban GSM" },
    { 25016,    "NTC" },
    { 25017,    "Ermak RMS" },
    { 25028,    "EXTEL" },
    { 25039,    "Uraltel" },
    { 25044,    "NC-GSM" },
    { 25091,    "Sonic Duo" },
    { 25092,    "Primtel" },
    { 25093,    "JSC Telecom XXI" },
    { 25099,    "Bee Line" },
    { 25501,    "UMC" },
    { 25502,    "WellCOM" },
    { 25503,    "Kyivstar" },
    { 25505,    "Golden Telecom" },
    { 25701,    "VELCOM" },
    { 25901,    "VOXTEL" },
    { 25902,    "MOLDCELL" },
    { 26001,    "Plus GSM" },
    { 26002,    "Era GSM" },
    { 26003,    "IDEA" },
    { 26201,    "T-Mobile" },
    { 26202,    "Vodafone D2" },
    { 26203,    "E-Plus" },
    { 26207,    "O2 - DE" },
    { 26213,    "Mobilcom" },
    { 26601,    "GIBTEL" },
    { 26801,    "Vodafone" },
    { 26803,    "OPTIMUS" },
    { 26806,    "TMN" },
    { 27001,    "LUXGSM" },
    { 27077,    "TANGO" },
    { 27201,    "Vodafone IRL" },
    { 27202,    "O2 - IRL" },
    { 27203,    "METEOR" },
    { 27401,    "SIMINN" },
    { 27402,    "TAL" },
    { 27404,    "Viking" },
    { 27601,    "AMC" },
    { 27602,    "Vodafone" },
    { 27801,    "Vodafone Malta" },
    { 27821,    "go mobile" },
    { 28001,    "CYTAGSM" },
    { 28201,    "GEOCELL" },
    { 28202,    "Magti GSM" },
    { 28203,    "GEO 03" },
    { 28301,    "ARMGSM" },
    { 28401,    "M-TEL GSM" },
    { 28601,    "TURKCELL" },
    { 28602,    "TELSIM" },
    { 28603,    "ARIA" },
    { 28604,    "AYCELL" },
    { 28801,    "FT GSM" },
    { 29001,    "TELE Greenland" },
    { 29340,    "SI.MOBIL" },
    { 29341,    "MOBITEL" },
    { 29401,    "MOBIMAK" },
    { 29501,    "TELECOM" },
    { 29502,    "MONTEL" },
    { 29505,    "FL1" },
    { 29577,    "LI TANGO" },
    { 30237,    "Microcell" },
    { 30272,    "Rogers AT&T" },
    { 31001,    "Cellnet" },
    { 31011,    "Wireless 2000" },
    { 31015,    "Cingular" },
    { 31016,    "T-Mobile" },
    { 31017,    "Cingular" },
    { 31018,    "Cingular" },
    { 31020,    "T-Mobile" },
    { 31021,    "T-Mobile" },
    { 31022,    "T-Mobile" },
    { 31023,    "T-Mobile" },
    { 31024,    "T-Mobile" },
    { 31025,    "T-Mobile" },
    { 31026,    "T-Mobile" },
    { 31027,    "T-Mobile" },
    { 31031,    "T-Mobile" },
    { 31034,    "WestLink" },
    { 31035,    "Carolina" },
    { 31038,    "AT&T Wireless" },
    { 31046,    "TMP Corp" },
    { 31058,    "T-Mobile" },
    { 31061,    "Epic Touch" },
    { 31063,    "AmeriLink" },
    { 31064,    "Einstein PCS" },
    { 31066,    "T-Mobile" },
    { 31067,    "Wireless 2000" },
    { 31068,    "NPI Wireless" },
    { 31069,    "Conestoga" },
    { 31074,    "Telemetrix" },
    { 31076,    "PTSI" },
    { 31077,    "Iowa Wireless" },
    { 31078,    "Airlink PCS" },
    { 31079,    "PinPoint" },
    { 31080,    "T-Mobile" },
    { 31098,    "AWS" },
    { 31114,    "Sprocket" },
    { 31601,    "Nextel" },
    { 33805,    "Digicel" },
    { 34001,    "Orange " },
    { 34020,    "Bouygues" },
    { 34430,    "APUA PCS" },
    { 35001,    "Telecom" },
    { 36251,    "Telcell GSM" },
    { 36801,    "C_Com" },
    { 37001,    "Orange" },
    { 40001,    "AZERCELL GSM" },
    { 40002,    "BAKCELL GSM 2000" },
    { 40101,    "K-MOBILE" },
    { 40102,    "K'CELL" },
    { 40401,    "ESSAR" },
    { 40405,    "CELFORCE" },
    { 40407,    "TATA CELLULAR" },
    { 40409,    "Reliance" },
    { 40410,    "AirTel" },
    { 40411,    "ESSAR" },
    { 40412,    "ESCOTEL" },
    { 40414,    "SPICE" },
    { 40415,    "ESSAR" },
    { 40418,    "Reliance" },
    { 40419,    "ESCOTEL" },
    { 40420,    "Orange" },
    { 40421,    "BPL MOBILE" },
    { 40422,    "AT&T" },
    { 40424,    "AT&T" },
    { 40427,    "BPL MOBILE" },
    { 40430,    "COMMAND" },
    { 40431,    "SPICE" },
    { 40436,    "Reliance" },
    { 40440,    "SKYCELL" },
    { 40441,    "RPG Cellular" },
    { 40442,    "AIRCEL" },
    { 40443,    "BPL MOBILE" },
    { 40444,    "AirTel" },
    { 40445,    "AirTel" },
    { 40446,    "BPL MOBILE" },
    { 40449,    "AirTel" },
    { 40450,    "Reliance" },
    { 40452,    "Reliance" },
    { 40456,    "ESCOTEL" },
    { 40460,    "ESSAR" },
    { 40467,    "Reliance" },
    { 40470,    "hexacom" },
    { 40485,    "Reliance" },
    { 41001,    "Mobilink" },
    { 41302,    "DIALOG" },
    { 41303,    "CELLTEL" },
    { 41401,    "MM 900" },
    { 41501,    "Cellis" },
    { 41503,    "LibanCell" },
    { 41601,    "Fastlink" },
    { 41677,    "MobileCom" },
    { 41702,    "Spacetel" },
    { 41709,    "MOBILE SYRIA" },
    { 41902,    "MTCNet" },
    { 41903,    "WATANIYA" },
    { 42001,    "Al-Jawal" },
    { 42007,    "EAE" },
    { 42102,    "Spacetel" },
    { 42202,    "OMAN MOBILE" },
    { 42402,    "ETISALAT" },
    { 42501,    "Orange" },
    { 42505,    "JAWWAL" },
    { 42601,    "MOBILE PLUS" },
    { 42701,    "QATARNET" },
    { 42899,    "MobiCom" },
    { 42901,    "NTC" },
    { 43211,    "TCI" },
    { 43214,    "KISH" },
    { 43401,    "Buztel" },
    { 43402,    "Uzmacom" },
    { 43404,    "UZB DAEWOO-GSM" },
    { 43405,    "Coscom" },
    { 43701,    "BITEL" },
    { 43801,    "BCTI" },
    { 45201,    "MOBIFONE" },
    { 45202,    "VINAFONE" },
    { 45400,    "CSL" },
    { 45401,    "NEW WORLD" },
    { 45404,    "Orange" },
    { 45406,    "SMC" },
    { 45410,    "NEW WORLD" },
    { 45412,    "PEOPLES" },
    { 45416,    "SUNDAY" },
    { 45500,    "SmarTone" },
    { 45501,    "CTMGSM" },
    { 45503,    "HT Macau" },
    { 45601,    "MobiTel" },
    { 45602,    "SAMART-GSM" },
    { 45701,    "LAO GSM" },
    { 46000,    "China Mobile" },
    { 46001,    "China Unicom" },
    { 46601,    "Far EasTone" },
    { 46606,    "TUNTEX" },
    { 46668,    "ACeS" },
    { 46688,    "KGT" },
    { 46692,    "Chunghwa" },
    { 46693,    "MobiTai" },
    { 46697,    "TWN GSM" },
    { 46699,    "TransAsia" },
    { 47001,    "GrameemPhone" },
    { 47002,    "AKTEL" },
    { 47003,    "ShebaWorld" },
    { 47019,    "Mobile 2000" },
    { 47201,    "DHIMOBILE" },
    { 50212,    "Maxis Mobile" },
    { 50213,    "TM Touch" },
    { 50216,    "DiGi" },
    { 50217,    "ADAM" },
    { 50219,    "CELCOM" },
    { 50501,    "MobileNet" },
    { 50502,    "OPTUS" },
    { 50503,    "Vodafone" },
    { 50508,    "One.Tel" },
    { 51000,    "ACeS" },
    { 51001,    "SATELINDOCEL" },
    { 51008,    "LIPPO TEL" },
    { 51010,    "TELKOMSEL" },
    { 51011,    "GSM-XL" },
    { 51021,    "INDOSAT" },
    { 51501,    "ISLACOM" },
    { 51502,    "Globe" },
    { 51503,    "SMART" },
    { 51505,    "Digitel" },
    { 51511,    "ACeS" },
    { 52001,    "AIS GSM" },
    { 52015,    "ACT Mobile" },
    { 52018,    "WP-1800" },
    { 52020,    "ACeS" },
    { 52023,    "HELLO" },
    { 52099,    "Orange" },
    { 52501,    "ST-GSM-SGP" },
    { 52502,    "ST-GSM1800-SGP" },
    { 52503,    "M1-GSM-SGP" },
    { 52504,    "SGP-M1-3GSM" },
    { 52505,    "STARHUB-SGP" },
    { 52811,    "BRU TSTCom" },
    { 53001,    "Vodafone" },
    { 53901,    "Tonga Comm." },
    { 54100,    "ACeS" },
    { 54101,    "SMILE" },
    { 54201,    "Vodafone" },
    { 54411,    "Blue Sky" },
    { 54601,    "MOBILIS" },
    { 54720,    "VINI" },
    { 55001,    "FSM" },
    { 60201,    "MobiNiL" },
    { 60202,    "CLICK GSM" },
    { 60301,    "AMN" },
    { 60400,    "Meditel" },
    { 60401,    "IAM" },
    { 60502,    "TUNICELL" },
    { 60801,    "ALIZE" },
    { 60802,    "SENTEL" },
    { 61001,    "MALITEL" },
    { 61101,    "MOBILIS" },
    { 61102,    "LAGUI" },
    { 61201,    "CORA" },
    { 61203,    "Ivoiris" },
    { 61205,    "TELECEL" },
    { 61302,    "CELTEL" },
    { 61402,    "CELTEL" },
    { 61501,    "TOGOCEL" },
    { 61601,    "LIBERCOM" },
    { 61602,    "Telecel Benin" },
    { 61603,    "BENINCELL" },
    { 61701,    "CELLPLUS" },
    { 61710,    "EMTEL" },
    { 61801,    "Omega" },
    { 62001,    "SPACEFON" },
    { 62002,    "ONEtouch" },
    { 62003,    "MOBITEL" },
    { 62100,    "MTN" },
    { 62120,    "ECONET" },
    { 62130,    "MTN" },
    { 62140,    "NITEL GSM" },
    { 62201,    "CELTEL" },
    { 62202,    "LIBERTIS" },
    { 62401,    "MTN-CAM" },
    { 62402,    "MOBILIS" },
    { 62501,    "CPV MOVEL" },
    { 62801,    "LIBERTIS" },
    { 62802,    "GO Celtel" },
    { 62803,    "CELTEL" },
    { 62901,    "CELTEL" },
    { 62910,    "LIBERTIS" },
    { 63001,    "CELLNET" },
    { 63002,    "CELTEL" },
    { 63004,    "CELLCO" },
    { 63089,    "OASIS" },
    { 63301,    "SEYCEL" },
    { 63310,    "AIRTEL" },
    { 63401,    "MobiTel" },
    { 63510,    "Rwandacell" },
    { 63601,    "ETMTN" },
    { 63701,    "BARAKAAT" },
    { 63902,    "Safaricom" },
    { 63903,    "KENCELL" },
    { 64001,    "TRITEL" },
    { 64002,    "MobiTel" },
    { 64003,    "ZANTEL" },
    { 64004,    "Vodacom" },
    { 64005,    "CELTEL" },
    { 64101,    "CelTel" },
    { 64110,    "MTN-UGANDA" },
    { 64111,    "UTL TELECEL" },
    { 64201,    "Spacetel" },
    { 64202,    "SAFARIS" },
    { 64301,    "mCel" },
    { 64501,    "ZAMCELL" },
    { 64502,    "TELECEL" },
    { 64601,    "Madacom" },
    { 64602,    "ANTARIS" },
    { 64700,    "Orange Reunion" },
    { 64710,    "SFR Reunion" },
    { 64801,    "NET*ONE" },
    { 64803,    "TELECEL" },
    { 64804,    "ECONET" },
    { 64901,    "MTC" },
    { 65001,    "CALLPOINT 90" },
    { 65010,    "CelTel" },
    { 65101,    "Vodacom" },
    { 65201,    "MASCOM" },
    { 65202,    "VISTA" },
    { 65310,    "SwaziMTN" },
    { 65501,    "Vodacom" },
    { 65507,    "Cell C (Pty) Ltd" },
    { 65510,    "MTN" },
    { 70601,    "PERSONAL" },
    { 70602,    "DIGICEL" },
    { 71610,    "TIM" },
    { 72207,    "UNIFON" },
    { 72234,    "Telecom Personal" },
    { 72235,    "PORT-HABLE" },
    { 73001,    "ENTEL PCS" },
    { 73010,    "ENTEL PCS" },
    { 73401,    "INFONET" },
    { 73402,    "DIGITEL" },
    { 73601,    "NUEVATEL" },
    { 73602,    "ENTEL" },
    { 74401,    "VOX" },
    { 74402,    "PY 02" },
    { 74601,    "ICMS" },
    { 90105,    "Thuraya" },
    { 302037,   "Microcell" },
    { 302072,   "Rogers AT&T" },
    { 302370,   "Microcell" },
    { 302720,   "Rogers AT&T" },
    { 310001,   "Cellnet" },
    { 310010,   "Cellnet" },
    { 310011,   "Wireless 2000" },
    { 310015,   "Cingular" },
    { 310016,   "T-Mobile" },
    { 310017,   "Cingular" },
    { 310018,   "Cingular" },
    { 310020,   "T-Mobile" },
    { 310021,   "T-Mobile" },
    { 310022,   "T-Mobile" },
    { 310023,   "T-Mobile" },
    { 310024,   "T-Mobile" },
    { 310025,   "T-Mobile" },
    { 310026,   "T-Mobile" },
    { 310027,   "T-Mobile" },
    { 310031,   "T-Mobile" },
    { 310034,   "WestLink" },
    { 310035,   "Carolina" },
    { 310038,   "AT&T Wireless" },
    { 310046,   "TMP Corp" },
    { 310058,   "T-Mobile" },
    { 310061,   "Epic Touch" },
    { 310063,   "AmeriLink" },
    { 310064,   "Einstein PCS" },
    { 310066,   "T-Mobile" },
    { 310067,   "Wireless 2000" },
    { 310068,   "NPI Wireless" },
    { 310069,   "Conestoga" },
    { 310074,   "Telemetrix" },
    { 310076,   "PTSI" },
    { 310077,   "Iowa Wireless" },
    { 310078,   "Airlink PCS" },
    { 310079,   "PinPoint" },
    { 310080,   "T-Mobile" },
    { 310098,   "AWS" },
    { 310110,   "Wireless 2000" },
    { 310150,   "Cingular" },
    { 310160,   "VoiceStream" },
    { 310170,   "Cingular" },
    { 310180,   "Cingular" },
    { 310200,   "VoiceStream" },
    { 310210,   "VoiceStream" },
    { 310220,   "VoiceStream" },
    { 310230,   "VoiceStream" },
    { 310240,   "VoiceStream" },
    { 310250,   "VoiceStream" },
    { 310260,   "VoiceStream" },
    { 310270,   "VoiceStream" },
    { 310310,   "VoiceStream" },
    { 310340,   "WestLink" },
    { 310350,   "Carolina" },
    { 310380,   "AT&T Wireless" },
    { 310410,   "Cingular" },
    { 310460,   "TMP Corp" },
    { 310580,   "PCS One" },
    { 310610,   "Epic Touch" },
    { 310630,   "AmeriLink" },
    { 310640,   "Einstein PCS" },
    { 310660,   "VoiceStream" },
    { 310670,   "Wireless 2000" },
    { 310680,   "NPI Wireless" },
    { 310690,   "Conestoga" },
    { 310740,   "Telemetrix" },
    { 310760,   "PTSI" },
    { 310770,   "Iowa Wireless" },
    { 310780,   "Airlink PCS" },
    { 310790,   "PinPoint" },
    { 310800,   "VoiceStream" },
    { 310980,   "AWS" },
    { 311014,   "Sprocket" },
    { 311140,   "Sprocket" },
    { 316001,   "Nextel" },
    { 316010,   "Nextel" },
    { 338005,   "Digicel" },
    { 338050,   "Digicel" },
    { 344030,   "APUA PCS" },
    { 344300,   "APUA PCS" },
    { 350001,   "Telecom" },
    { 350010,   "Telecom" },
    { 362051,   "Telcell GSM" },
    { 362510,   "Telcell GSM" },
    { 368001,   "C_Com" },
    { 368010,   "C_Com" },
    { 370001,   "Orange" },
    { 370010,   "Orange" },
    { 544011,   "Blue Sky" },
    { 544110,   "Blue Sky" },
    { 550001,   "FSM" },
    { 550010,   "FSM" },
    { 730001,   "ENTEL PCS" },
    { 730010,   "ENTEL PCS" },
    { 730100,   "ENTEL PCS" },
    { 734001,   "INFONET" },
    { 734002,   "DIGITEL" },
    { 734010,   "INFONET" },
    { 734020,   "DIGITEL" },
    { 736001,   "NUEVATEL" },
    { 736010,   "NUEVATEL" },
    { 744001,   "VOX" },
    { 744010,   "VOX" },
    { 901005,   "Thuraya" },
    { 901050,   "Thuraya" },
#else
#include "network1.lst"
#endif
};
#define NUM_OPERATORNAMES   (sizeof(g_rgonmOperatorNames) / sizeof(g_rgonmOperatorNames[0]))

#else

#define UNKNOWN_COUNTRY_CODE ("--")
#define MCC_LEN (3)

//
// Long operator names
//
static const OPERATORNAMEMAP g_rgonmOperatorNames[] =
{
#ifdef USE_MICROSOFT_PROVIDER_LIST
    { 20201,    "Cosmote",          "GR" },
    { 20205,    "Vodafone GR",      "GR" },
    { 20210,    "TELESTET",         "GR" },
    { 20404,    "Vodafone NL",      "NL" },
    { 20408,    "KPN",              "NL" },
    { 20412,    "O2 - NL",          "NL" },
    { 20416,    "Ben",              "NL" },
    { 20420,    "dutchtone",        "NL" },
    { 20601,    "Proximus",         "BE" },
    { 20610,    "Mobistar",         "BE" },
    { 20620,    "Orange",           "BE" },
    { 20801,    "Orange",           "FR" },
    { 20810,    "SFR",              "FR" },
    { 20820,    "BOUYGTEL",         "FR" },
    { 21303,    "Mobiland",         "AD" },
    { 21401,    "Vodafone E",       "ES" },
    { 21402,    "MoviStar",         "ES" },
    { 21403,    "AMENA",            "ES" },
    { 21404,    "Xfera",            "ES" },
    { 21407,    "MoviStar",         "ES" },
    { 21601,    "Pannon GSM",       "HU" },
    { 21630,    "Westel",           "HU" },
    { 21670,    "Vodafone",         "HU" },
    { 21803,    "ERONET",           "BA" },
    { 21805,    "Mobilna Srpska",   "BA" },
    { 21890,    "GSM BiH",          "BA" },
    { 21901,    "CRONET",           "HR" },
    { 21910,    "VIP",              "HR" },
    { 22001,    "MOBTEL",           "YU" },
    { 22002,    "ProMonte",         "YU" },
    { 22003,    "Telekom Srbija",   "YU" },
    { 22004,    "MONET",            "YU" },
    { 22201,    "TIM",              "IT" },
    { 22210,    "Vodafone IT",      "IT" },
    { 22288,    "WIND",             "IT" },
    { 22298,    "Blu SpA",          "IT" },
    { 22601,    "CONNEX",           "RO" },
    { 22603,    "Cosmorom",         "RO" },
    { 22610,    "dialog",           "RO" },
    { 22801,    "Swiss GSM",        "CH" },
    { 22802,    "sunrise",          "CH" },
    { 22803,    "Orange",           "CH" },
    { 23001,    "PAEGAS",           "CZ" },
    { 23002,    "EUROTEL",          "CZ" },
    { 23003,    "OSKAR",            "CZ" },
    { 23101,    "GLOBTEL",          "SK" },
    { 23102,    "EUROTEL",          "SK" },
    { 23201,    "A1",               "AT" },
    { 23203,    "T-Mobile",         "AT" },
    { 23205,    "ONE",              "AT" },
    { 23207,    "tele.ring",        "AT" },
    { 23410,    "O2 - UK",          "GB" },
    { 23415,    "Vodafone",         "GB" },
    { 23430,    "T-Mobile UK",      "GB" },
    { 23431,    "T-Mobile UK",      "GB" },
    { 23432,    "T-Mobile UK",      "GB" },
    { 23433,    "Orange",           "GB" },
    { 23450,    "JT GSM",           "GB" },
    { 23455,    "GUERNSEY TEL",     "GB" },
    { 23458,    "MANX",             "GB" },
    { 23801,    "TDK-MOBIL",        "DK" },
    { 23802,    "SONOFON",          "DK" },
    { 23820,    "Telia",            "DK" },
    { 23830,    "Orange",           "DK" },
    { 24001,    "Telia S",          "SE" },
    { 24007,    "IQ",               "SE" },
    { 24008,    "Vodafone",         "SE" },
    { 24201,    "TELENOR",          "NO" },
    { 24202,    "NetCom",           "NO" },
    { 24403,    "Telia",            "FI" },
    { 24405,    "RADIOLINJA",       "FI" },
    { 24409,    "FINNET",           "FI" },
    { 24412,    "2G",               "FI" },
    { 24414,    "AMT",              "FI" },
    { 24491,    "SONERA",           "FI" },
    { 24601,    "OMNITEL",          "LT" },
    { 24602,    "Bite GSM",         "LT" },
    { 24603,    "TELE2",            "LT" },
    { 24701,    "LMT GSM",          "LV" },
    { 24702,    "BALTCOM",          "LV" },
    { 24801,    "EMT GSM",          "EE" },
    { 24802,    "RLE",              "EE" },
    { 24803,    "Q GSM",            "EE" },
    { 25001,    "MTS",              "RU" },
    { 25002,    "NorthWest GSM",    "RU" },
    { 25003,    "NCC",              "RU" },
    { 25005,    "SCS",              "RU" },
    { 25007,    "SMARTS",           "RU" },
    { 25010,    "DTC",              "RU" },
    { 25011,    "Orensot",          "RU" },
    { 25012,    "Far East",         "RU" },
    { 25013,    "Kuban GSM",        "RU" },
    { 25016,    "NTC",              "RU" },
    { 25017,    "Ermak RMS",        "RU" },
    { 25028,    "EXTEL",            "RU" },
    { 25039,    "Uraltel",          "RU" },
    { 25044,    "NC-GSM",           "RU" },
    { 25091,    "Sonic Duo",        "RU" },
    { 25092,    "Primtel",          "RU" },
    { 25093,    "JSC Telecom XXI",  "RU" },
    { 25099,    "Bee Line",         "RU" },
    { 25501,    "UMC",              "UA" },
    { 25502,    "WellCOM",          "UA" },
    { 25503,    "Kyivstar",         "UA" },
    { 25505,    "Golden Telecom",   "UA" },
    { 25701,    "VELCOM",           "BY" },
    { 25901,    "VOXTEL",           "MD" },
    { 25902,    "MOLDCELL",         "MD" },
    { 26001,    "Plus GSM",         "PL" },
    { 26002,    "Era GSM",          "PL" },
    { 26003,    "IDEA",             "PL" },
    { 26201,    "T-Mobile",         "DE" },
    { 26202,    "Vodafone D2",      "DE" },
    { 26203,    "E-Plus",           "DE" },
    { 26207,    "O2 - DE",          "DE" },
    { 26213,    "Mobilcom",         "DE" },
    { 26601,    "GIBTEL",           "GI" },
    { 26801,    "Vodafone",         "PT" },
    { 26803,    "OPTIMUS",          "PT" },
    { 26806,    "TMN",              "PT" },
    { 27001,    "LUXGSM",           "LU" },
    { 27077,    "TANGO",            "LU" },
    { 27201,    "Vodafone IRL",     "IE" },
    { 27202,    "O2 - IRL",         "IE" },
    { 27203,    "METEOR",           "IE" },
    { 27401,    "SIMINN",           "IS" },
    { 27402,    "TAL",              "IS" },
    { 27404,    "Viking",           "IS" },
    { 27601,    "AMC",              "AL" },
    { 27602,    "Vodafone",         "AL" },
    { 27801,    "Vodafone Malta",   "MT" },
    { 27821,    "go mobile",        "MT" },
    { 28001,    "CYTAGSM",          "CY" },
    { 28201,    "GEOCELL",          "GE" },
    { 28202,    "Magti GSM",        "GE" },
    { 28203,    "GEO 03",           "GE" },
    { 28301,    "ARMGSM",           "AM" },
    { 28401,    "M-TEL GSM",        "BG" },
    { 28601,    "TURKCELL",         "TR" },
    { 28602,    "TELSIM",           "TR" },
    { 28603,    "ARIA",             "TR" },
    { 28604,    "AYCELL",           "TR" },
    { 28801,    "FT GSM",           "FO" },
    { 29001,    "TELE Greenland",   "GR" },
    { 29340,    "SI.MOBIL",         "SI" },
    { 29341,    "MOBITEL",          "SI" },
    { 29401,    "MOBIMAK",          "MK" },
    { 29501,    "TELECOM",          "LI" },
    { 29502,    "MONTEL",           "LI" },
    { 29505,    "FL1",              "LI" },
    { 29577,    "LI TANGO",         "LI" },
    { 30237,    "Microcell",        "CA" },
    { 30272,    "Rogers AT&T",      "CA" },
    { 31001,    "Cellnet",          "US" },
    { 31011,    "Wireless 2000",    "US" },
    { 31015,    "Cingular",         "US" },
    { 31016,    "T-Mobile",         "US" },
    { 31017,    "Cingular",         "US" },
    { 31018,    "Cingular",         "US" },
    { 31020,    "T-Mobile",         "US" },
    { 31021,    "T-Mobile",         "US" },
    { 31022,    "T-Mobile",         "US" },
    { 31023,    "T-Mobile",         "US" },
    { 31024,    "T-Mobile",         "US" },
    { 31025,    "T-Mobile",         "US" },
    { 31026,    "T-Mobile",         "US" },
    { 31027,    "T-Mobile",         "US" },
    { 31031,    "T-Mobile",         "US" },
    { 31034,    "WestLink",         "US" },
    { 31035,    "Carolina",         "US" },
    { 31038,    "AT&T Wireless",    "US" },
    { 31046,    "TMP Corp",         "US" },
    { 31058,    "T-Mobile",         "US" },
    { 31061,    "Epic Touch",       "US" },
    { 31063,    "AmeriLink",        "US" },
    { 31064,    "Einstein PCS",     "US" },
    { 31066,    "T-Mobile",         "US" },
    { 31067,    "Wireless 2000",    "US" },
    { 31068,    "NPI Wireless",     "US" },
    { 31069,    "Conestoga",        "US" },
    { 31074,    "Telemetrix",       "US" },
    { 31076,    "PTSI",             "US" },
    { 31077,    "Iowa Wireless",    "US" },
    { 31078,    "Airlink PCS",      "US" },
    { 31079,    "PinPoint",         "US" },
    { 31080,    "T-Mobile",         "US" },
    { 31098,    "AWS",              "US" },
    { 31114,    "Sprocket",         UNKNOWN_COUNTRY_CODE },
    { 31601,    "Nextel",           UNKNOWN_COUNTRY_CODE },
    { 33805,    "Digicel",          "JM" },
    { 34001,    "Orange ",          "FW" },
    { 34020,    "Bouygues",         "FW" },
    { 34430,    "APUA PCS",         "AG" },
    { 35001,    "Telecom",          "BM" },
    { 36251,    "Telcell GSM",      "AN" },
    { 36801,    "C_Com",            "CU" },
    { 37001,    "Orange",           "DO" },
    { 40001,    "AZERCELL GSM",     "AZ" },
    { 40002,    "BAKCELL GSM 2000", "AZ" },
    { 40101,    "K-MOBILE",         "KZ" },
    { 40102,    "K'CELL",           "KZ" },
    { 40401,    "ESSAR",            "IN" },
    { 40405,    "CELFORCE",         "IN" },
    { 40407,    "TATA CELLULAR",    "IN" },
    { 40409,    "Reliance",         "IN" },
    { 40410,    "AirTel",           "IN" },
    { 40411,    "ESSAR",            "IN" },
    { 40412,    "ESCOTEL",          "IN" },
    { 40414,    "SPICE",            "IN" },
    { 40415,    "ESSAR",            "IN" },
    { 40418,    "Reliance",         "IN" },
    { 40419,    "ESCOTEL",          "IN" },
    { 40420,    "Orange",           "IN" },
    { 40421,    "BPL MOBILE",       "IN" },
    { 40422,    "AT&T",             "IN" },
    { 40424,    "AT&T",             "IN" },
    { 40427,    "BPL MOBILE",       "IN" },
    { 40430,    "COMMAND",          "IN" },
    { 40431,    "SPICE",            "IN" },
    { 40436,    "Reliance",         "IN" },
    { 40440,    "SKYCELL",          "IN" },
    { 40441,    "RPG Cellular",     "IN" },
    { 40442,    "AIRCEL",           "IN" },
    { 40443,    "BPL MOBILE",       "IN" },
    { 40444,    "AirTel",           "IN" },
    { 40445,    "AirTel",           "IN" },
    { 40446,    "BPL MOBILE",       "IN" },
    { 40449,    "AirTel",           "IN" },
    { 40450,    "Reliance",         "IN" },
    { 40452,    "Reliance",         "IN" },
    { 40456,    "ESCOTEL",          "IN" },
    { 40460,    "ESSAR",            "IN" },
    { 40467,    "Reliance",         "IN" },
    { 40470,    "hexacom",          "IN" },
    { 40485,    "Reliance",         "IN" },
    { 41001,    "Mobilink",         "PK" },
    { 41302,    "DIALOG",           "LK" },
    { 41303,    "CELLTEL",          "LK" },
    { 41401,    "MM 900",           "MM" },
    { 41501,    "Cellis",           "LB" },
    { 41503,    "LibanCell",        "LB" },
    { 41601,    "Fastlink",         "JO" },
    { 41677,    "MobileCom",        "JO" },
    { 41702,    "Spacetel",         "SY" },
    { 41709,    "MOBILE SYRIA",     "SY" },
    { 41902,    "MTCNet",           "KW" },
    { 41903,    "WATANIYA",         "KW" },
    { 42001,    "Al-Jawal",         "SA" },
    { 42007,    "EAE",              "SA" },
    { 42102,    "Spacetel",         "YE" },
    { 42202,    "OMAN MOBILE",      "OM" },
    { 42402,    "ETISALAT",         "AE" },
    { 42501,    "Orange",           "IL" },
    { 42505,    "JAWWAL",           "IL" },
    { 42601,    "MOBILE PLUS",      "BH" },
    { 42701,    "QATARNET",         "QA" },
    { 42899,    "MobiCom",          "MN" },
    { 42901,    "NTC",              "NP" },
    { 43211,    "TCI",              "IR" },
    { 43214,    "KISH",             "IR" },
    { 43401,    "Buztel",           "UZ" },
    { 43402,    "Uzmacom",          "UZ" },
    { 43404,    "UZB DAEWOO-GSM",   "UZ" },
    { 43405,    "Coscom",           "UZ" },
    { 43701,    "BITEL",            "KG" },
    { 43801,    "BCTI",             "TM" },
    { 45201,    "MOBIFONE",         "VN" },
    { 45202,    "VINAFONE",         "VN" },
    { 45400,    "CSL",              "HK" },
    { 45401,    "NEW WORLD",        "HK" },
    { 45404,    "Orange",           "HK" },
    { 45406,    "SMC",              "HK" },
    { 45410,    "NEW WORLD",        "HK" },
    { 45412,    "PEOPLES",          "HK" },
    { 45416,    "SUNDAY",           "HK" },
    { 45500,    "SmarTone",         UNKNOWN_COUNTRY_CODE }, //macau
    { 45501,    "CTMGSM",           UNKNOWN_COUNTRY_CODE },
    { 45503,    "HT Macau",         UNKNOWN_COUNTRY_CODE },
    { 45601,    "MobiTel",          "KH" },
    { 45602,    "SAMART-GSM",       "KH" },
    { 45701,    "LAO GSM",          "LA" },
    { 46000,    "China Mobile",     "CN" },
    { 46001,    "China Unicom",     "CN" },
    { 46601,    "Far EasTone",      "TW" },
    { 46606,    "TUNTEX",           "TW" },
    { 46668,    "ACeS",             "TW" },
    { 46688,    "KGT",              "TW" },
    { 46692,    "Chunghwa",         "TW" },
    { 46693,    "MobiTai",          "TW" },
    { 46697,    "TWN GSM",          "TW" },
    { 46699,    "TransAsia",        "TW" },
    { 47001,    "GrameemPhone",     "BD" },
    { 47002,    "AKTEL",            "BD" },
    { 47003,    "ShebaWorld",       "BD" },
    { 47019,    "Mobile 2000",      "BD" },
    { 47201,    "DHIMOBILE",        "MV" },
    { 50212,    "Maxis Mobile",     "MY" },
    { 50213,    "TM Touch",         "MY" },
    { 50216,    "DiGi",             "MY" },
    { 50217,    "ADAM",             "MY" },
    { 50219,    "CELCOM",           "MY" },
    { 50501,    "MobileNet",        "AU" },
    { 50502,    "OPTUS",            "AU" },
    { 50503,    "Vodafone",         "AU" },
    { 50508,    "One.Tel",          "AU" },
    { 51000,    "ACeS",             "ID" },
    { 51001,    "SATELINDOCEL",     "ID" },
    { 51008,    "LIPPO TEL",        "ID" },
    { 51010,    "TELKOMSEL",        "ID" },
    { 51011,    "GSM-XL",           "ID" },
    { 51021,    "INDOSAT",          "ID" },
    { 51501,    "ISLACOM",          "PH" },
    { 51502,    "Globe",            "PH" },
    { 51503,    "SMART",            "PH" },
    { 51505,    "Digitel",          "PH" },
    { 51511,    "ACeS",             "PH" },
    { 52001,    "AIS GSM",          "TH" },
    { 52015,    "ACT Mobile",       "TH" },
    { 52018,    "WP-1800",          "TH" },
    { 52020,    "ACeS",             "TH" },
    { 52023,    "HELLO",            "TH" },
    { 52099,    "Orange",           "TH" },
    { 52501,    "ST-GSM-SGP",       "SG" },
    { 52502,    "ST-GSM1800-SGP",   "SG" },
    { 52503,    "M1-GSM-SGP",       "SG" },
    { 52504,    "SGP-M1-3GSM",      "SG" },
    { 52505,    "STARHUB-SGP",      "SG" },
    { 52811,    "BRU TSTCom",       "BN" },
    { 53001,    "Vodafone",         "NZ" },
    { 53901,    "Tonga Comm.",      "TO" },
    { 54100,    "ACeS",             "VU" },
    { 54101,    "SMILE",            "VU" },
    { 54201,    "Vodafone",         "FJ" },
    { 54411,    "Blue Sky",         "AS" },
    { 54601,    "MOBILIS",          "NC" },
    { 54720,    "VINI",             "PF" },
    { 55001,    "FSM",              "FM" },
    { 60201,    "MobiNiL",          "EG" },
    { 60202,    "CLICK GSM",        "EG" },
    { 60301,    "AMN",              "DZ" },
    { 60400,    "Meditel",          "MA" },
    { 60401,    "IAM",              "MA" },
    { 60502,    "TUNICELL",         "TN" },
    { 60801,    "ALIZE",            "SN" },
    { 60802,    "SENTEL",           "SN" },
    { 61001,    "MALITEL",          "ML" },
    { 61101,    "MOBILIS",          "GN" },
    { 61102,    "LAGUI",            "GN" },
    { 61201,    "CORA",             "CI" },
    { 61203,    "Ivoiris",          "CI" },
    { 61205,    "TELECEL",          "CI" },
    { 61302,    "CELTEL",           "BF" },
    { 61402,    "CELTEL",           "NE" },
    { 61501,    "TOGOCEL",          "TG" },
    { 61601,    "LIBERCOM",         "BJ" },
    { 61602,    "Telecel Benin",    "BJ" },
    { 61603,    "BENINCELL",        "BJ" },
    { 61701,    "CELLPLUS",         "MU" },
    { 61710,    "EMTEL",            "MU" },
    { 61801,    "Omega",            "LR" },
    { 62001,    "SPACEFON",         "GH" },
    { 62002,    "ONEtouch",         "GH" },
    { 62003,    "MOBITEL",          "GH" },
    { 62100,    "MTN",              "NG" },
    { 62120,    "ECONET",           "NG" },
    { 62130,    "MTN",              "NG" },
    { 62140,    "NITEL GSM",        "NG" },
    { 62201,    "CELTEL",           "TD" },
    { 62202,    "LIBERTIS",         "TD" },
    { 62401,    "MTN-CAM",          "CM" },
    { 62402,    "MOBILIS",          "CM" },
    { 62501,    "CPV MOVEL",        "CV" },
    { 62801,    "LIBERTIS",         "GA" },
    { 62802,    "GO Celtel",        "GA" },
    { 62803,    "CELTEL",           "GA" },
    { 62901,    "CELTEL",           "CG" },
    { 62910,    "LIBERTIS",         "CG" },
    { 63001,    "CELLNET",          "CD" },
    { 63002,    "CELTEL",           "CD" },
    { 63004,    "CELLCO",           "CD" },
    { 63089,    "OASIS",            "CD" },
    { 63301,    "SEYCEL",           "SC" },
    { 63310,    "AIRTEL",           "SC" },
    { 63401,    "MobiTel",          "MZ" },
    { 63510,    "Rwandacell",       "RW" },
    { 63601,    "ETMTN",            "ET" },
    { 63701,    "BARAKAAT",         "SO" },
    { 63902,    "Safaricom",        "KE" },
    { 63903,    "KENCELL",          "KE" },
    { 64001,    "TRITEL",           "TZ" },
    { 64002,    "MobiTel",          "TZ" },
    { 64003,    "ZANTEL",           "TZ" },
    { 64004,    "Vodacom",          "TZ" },
    { 64005,    "CELTEL",           "TZ" },
    { 64101,    "CelTel",           "UG" },
    { 64110,    "MTN-UGANDA",       "UG" },
    { 64111,    "UTL TELECEL",      "UG" },
    { 64201,    "Spacetel",         "BI" },
    { 64202,    "SAFARIS",          "BI" },
    { 64301,    "mCel",             UNKNOWN_COUNTRY_CODE }, //???
    { 64501,    "ZAMCELL",          UNKNOWN_COUNTRY_CODE }, //???
    { 64502,    "TELECEL",          UNKNOWN_COUNTRY_CODE },
    { 64601,    "Madacom",          "MG" },
    { 64602,    "ANTARIS",          "MG" },
    { 64700,    "Orange Reunion",   "RE" },
    { 64710,    "SFR Reunion",      "RE" },
    { 64801,    "NET*ONE",          "ZW" },
    { 64803,    "TELECEL",          "ZW" },
    { 64804,    "ECONET",           "ZW" },
    { 64901,    "MTC",              "NA" },
    { 65001,    "CALLPOINT 90",     "MW" },
    { 65010,    "CelTel",           "MW" },
    { 65101,    "Vodacom",          "LS" },
    { 65201,    "MASCOM",           "BW" },
    { 65202,    "VISTA",            "BW" },
    { 65310,    "SwaziMTN",         "SZ" },
    { 65501,    "Vodacom",          "ZA" },
    { 65507,    "Cell C (Pty) Ltd", "ZA" },
    { 65510,    "MTN",              "ZA" },
    { 70601,    "PERSONAL",         "SV" },
    { 70602,    "DIGICEL",          "SV" },
    { 71610,    "TIM",              "PE" },
    { 72207,    "UNIFON",           "AR" },
    { 72234,    "Telecom Personal", "AR" },
    { 72235,    "PORT-HABLE",       "AR" },
    { 73001,    "ENTEL PCS",        "CL" },
    { 73010,    "ENTEL PCS",        "CL" },
    { 73401,    "INFONET",          "VE" },
    { 73402,    "DIGITEL",          "VE" },
    { 73601,    "NUEVATEL",         "BO" },
    { 73602,    "ENTEL",            "BO" },
    { 74401,    "VOX",              "PY" },
    { 74402,    "PY 02",            "PY" },
    { 74601,    "ICMS",             "SR" },
    { 90105,    "Thuraya",          UNKNOWN_COUNTRY_CODE }, //???
#else
#include "network2.lst"
#endif
};
#define NUM_OPERATORNAMES   (sizeof(g_rgonmOperatorNames) / sizeof(g_rgonmOperatorNames[0]))

#endif


//
// Services
//
static const DWORD g_rgdwServices[] =
{
    RIL_SERVICE_MODEM_ASYNC,            // 1
    RIL_SERVICE_MODEM_SYNC,             // 2
    RIL_SERVICE_PADACCESS_ASYNC,        // 3
    RIL_SERVICE_PACKETACCESS_SYNC,      // 4
    RIL_SERVICE_VOICE,                  // 5
};
#define NUM_SERVICES    (sizeof(g_rgdwServices) / sizeof(DWORD))


//
// Operator status values
//
static const DWORD g_rgdwOperStats[] =
{
    RIL_OPSTATUS_UNKNOWN,       // 0
    RIL_OPSTATUS_AVAILABLE,     // 1
    RIL_OPSTATUS_CURRENT,       // 2
    RIL_OPSTATUS_FORBIDDEN,     // 3
};
#define NUM_OPERSTATS   (sizeof(g_rgdwOperStats) / sizeof(DWORD))


//
// Operator selection modes
//
static const DWORD g_rgdwOperSelModes[] =
{
    RIL_OPSELMODE_AUTOMATIC,        // 0
    RIL_OPSELMODE_MANUAL,           // 1
    -1,                             // 2
    -1,                             // 3
    RIL_OPSELMODE_MANUALAUTOMATIC,  // 4
};
#define NUM_OPSELMODES  (sizeof(g_rgdwOperSelModes) / sizeof(DWORD))




//
// Comparison routine used for binary search below
//
static int _cdecl BSCompareOperatorNames(const void* pElem1, const void* pElem2)
{
    int nRet;
    UINT nNumericName1 = ((OPERATORNAMEMAP*)pElem1)->nNumericName;
    UINT nNumericName2 = ((OPERATORNAMEMAP*)pElem2)->nNumericName;

    if (nNumericName1 < nNumericName2) {
        nRet = -1;
    } else if (nNumericName1 == nNumericName2) {
        nRet = 0;
    } else {
        nRet = 1;
    }
    return nRet;
}

#ifdef X86_EMUL

//
//
//
void GetLongOperatorName(RILOPERATORNAMES* pronNames)
{
    TBD_FUNCTION(GetLongOperatorName);

    OPERATORNAMEMAP onmKey;
    OPERATORNAMEMAP* ponmFound;
    TCHAR tszLongName[MAXLENGTH_OPERATOR_LONG];

    // Long operator name precedence:
    // 1) Value in registry, keyed by network number.
    // 2) Value in hard-coded table above.
    // 3) Value from radio response.
    // 4) Numeric value.

    // Make sure we have a numeric name
    if ((RIL_PARAM_ON_NUMNAME & pronNames->dwParams)) {
        // Now see if we have a mapping for this numeric name specified in the registry
        if (GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyOperNames, TString(pronNames->szNumName), tszLongName, MAXLENGTH_OPERATOR_LONG)) {
            // Yes, we do -- use it
            strncpyz(pronNames->szLongName, AnsiString(tszLongName), MAXLENGTH_OPERATOR_LONG);
            pronNames->dwParams |= RIL_PARAM_ON_LONGNAME;
        } else {
            // Set up the key for binary search
            memset(&onmKey, 0x00, sizeof(onmKey));
            onmKey.nNumericName = atoi(pronNames->szNumName);

            // It's a good idea to check the g_rgonmOperatorNames table periodically
// #define VERIFY_OPERATORNAMEMAP_TABLE
#if defined(VERIFY_OPERATORNAMEMAP_TABLE)
            for(int i = 0 ; i < NUM_OPERATORNAMES-1 ; i++)
            {
                TBD_ASSERT(g_rgonmOperatorNames[i].nNumericName < g_rgonmOperatorNames[i+1].nNumericName);  // Entries must be sorted
                TBD_ASSERT(strlen(g_rgonmOperatorNames[i].szLongName) <= 16);  // Operator names should not exceed 16 characters
            }
            TBD_ASSERT(i == NUM_OPERATORNAMES-1);  // Made it to the second-to-last entry
            TBD_ASSERT(strlen(g_rgonmOperatorNames[i].szLongName) <= 16);  // Operator names should not exceed 16 characters
#endif // defined(VERIFY_OPERATORNAMEMAP_TABLE)

            // Perform binary search on the operator name map
            ponmFound = (OPERATORNAMEMAP*)bsearch(&onmKey, g_rgonmOperatorNames, NUM_OPERATORNAMES, sizeof(OPERATORNAMEMAP), BSCompareOperatorNames);
            if (ponmFound) {
                // Copy the found long name into the provided buffer
                strncpyz(pronNames->szLongName, ponmFound->szLongName, MAXLENGTH_OPERATOR_LONG);
                pronNames->dwParams |= RIL_PARAM_ON_LONGNAME;
            }
        }

        // If we still don't have a long name, then fill in with the numeric name
        if (!(RIL_PARAM_ON_LONGNAME & pronNames->dwParams))
        {
            strncpyz(pronNames->szLongName, pronNames->szNumName, MAXLENGTH_OPERATOR_LONG);
            pronNames->dwParams |= RIL_PARAM_ON_LONGNAME;
        }
    }
}

#else

//
//
//
void GetLongOperatorName(RILOPERATORNAMES* pronNames)
{
    TBD_FUNCTION(GetLongOperatorName);

    OPERATORNAMEMAP onmKey;
    OPERATORNAMEMAP* ponmFound;
    TCHAR tszLongName[MAXLENGTH_OPERATOR_LONG];

    // Long operator name precedence:
    // 1) Value in registry, keyed by network number.
    // 2) Value in hard-coded table above.
    // 3) Value from radio response.
    // 4) Numeric value.

    // Make sure we have a numeric name
    if ((RIL_PARAM_ON_NUMNAME & pronNames->dwParams)) {
        // Now see if we have a mapping for this numeric name specified in the registry
        if (GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyOperNames, TString(pronNames->szNumName), tszLongName, MAXLENGTH_OPERATOR_LONG)) {
            // Yes, we do -- use it
            strncpyz(pronNames->szLongName, AnsiString(tszLongName), MAXLENGTH_OPERATOR_LONG);
            pronNames->dwParams |= RIL_PARAM_ON_LONGNAME;
        } else {
            // Set up the key for binary search
            memset(&onmKey, 0x00, sizeof(onmKey));

            // It's a good idea to check the g_rgonmOperatorNames table periodically
//#define VERIFY_OPERATORNAMEMAP_TABLE
#if defined(VERIFY_OPERATORNAMEMAP_TABLE)
            for(int i = 0 ; i < NUM_OPERATORNAMES-1 ; i++) {
                TBD_ASSERT(g_rgonmOperatorNames[i].nNumericName < g_rgonmOperatorNames[i+1].nNumericName);  // Entries must be sorted
                TBD_ASSERT(g_rgonmOperatorNames[i].szLongName && (strlen(g_rgonmOperatorNames[i].szLongName) <= 16));  // Operator names should not exceed 16 characters
                TBD_ASSERT(g_rgonmOperatorNames[i].szCountryCode && (strlen(g_rgonmOperatorNames[i].szCountryCode) <= 4));  // country code should not exceed 4 characters
            }
            TBD_ASSERT(i == NUM_OPERATORNAMES-1);  // Made it to the second-to-last entry
            TBD_ASSERT(g_rgonmOperatorNames[i].szLongName && (strlen(g_rgonmOperatorNames[i].szLongName) <= 16));  // Operator names should not exceed 16 characters
            TBD_ASSERT(g_rgonmOperatorNames[i].szCountryCode && (strlen(g_rgonmOperatorNames[i].szCountryCode) <= 4));  // country code should not exceed 4 characters
#endif // defined(VERIFY_OPERATORNAMEMAP_TABLE)

            // Perform binary search on the operator name map

            //direct search first
            onmKey.nNumericName = atoi(pronNames->szNumName);
            ponmFound = (OPERATORNAMEMAP*)bsearch(&onmKey, g_rgonmOperatorNames, NUM_OPERATORNAMES, sizeof(OPERATORNAMEMAP), BSCompareOperatorNames);
            if ((NULL == ponmFound) && (6 == strlen(pronNames->szNumName))) {
                //handle 2 unusual PCS 1900 cases..
                DWORD dwTemp;
                //try the YYY0XX case first...(this needs to be done first because of proper ambiguity resolution)
                onmKey.nNumericName = atoi(pronNames->szNumName);
                dwTemp = onmKey.nNumericName % 100;
                TBD_ASSERT((0 <= dwTemp) && (100 > dwTemp));
                onmKey.nNumericName -= dwTemp;
                TBD_ASSERT(0 == (onmKey.nNumericName % 100));
                onmKey.nNumericName /= 10;
                onmKey.nNumericName += dwTemp;
                ponmFound = (OPERATORNAMEMAP*)bsearch(&onmKey, g_rgonmOperatorNames, NUM_OPERATORNAMES, sizeof(OPERATORNAMEMAP), BSCompareOperatorNames);
                if (NULL == ponmFound) {
                    //try the YYYXX0 case next...
                    onmKey.nNumericName = atoi(pronNames->szNumName);
                    onmKey.nNumericName /= 10;
                    ponmFound = (OPERATORNAMEMAP*)bsearch(&onmKey, g_rgonmOperatorNames, NUM_OPERATORNAMES, sizeof(OPERATORNAMEMAP), BSCompareOperatorNames);
                }
            }
            if (ponmFound) {
                // Copy the found long name into the provided buffer
                strncpyz(pronNames->szLongName, ponmFound->szLongName, MAXLENGTH_OPERATOR_LONG);
                strncpyz(pronNames->szCountryCode, ponmFound->szCountryCode, MAXLENGTH_OPERATOR_COUNTRY_CODE);
                pronNames->dwParams |= RIL_PARAM_ON_LONGNAME|RIL_PARAM_ON_COUNTRY_CODE;
            }
        }

        // If we still don't have a long name, then fill in with the numeric name
        if (!(RIL_PARAM_ON_LONGNAME & pronNames->dwParams))
        {
            strncpyz(pronNames->szLongName, pronNames->szNumName, MAXLENGTH_OPERATOR_LONG);
            strncpyz(pronNames->szCountryCode, UNKNOWN_COUNTRY_CODE, MAXLENGTH_OPERATOR_COUNTRY_CODE);
            pronNames->dwParams |= RIL_PARAM_ON_LONGNAME|RIL_PARAM_ON_COUNTRY_CODE;
        }
    }
}

#endif

//
//
//
static HRESULT ParseGetSubscriberNumbers(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetSubscriberNumbers);
    UINT i;
    UINT nValue;
    UINT nUsed = 0;
    UINT nAllocated = 0;
    DWORD dwCurrentAddressId = 0;
    char szAddress[MAXLENGTH_ADDRESS];
    RILSUBSCRIBERINFO* rgrsi = NULL;
    HRESULT hr = S_OK;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>"
    if (!ParseRspPrefix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    // Parse "+CNUM: "
    while (MatchStringBeginning(szRsp, "+CNUM: ", szRsp)) {
        if (nUsed == nAllocated) {
            if (!AllocateOrReallocateStorage((BYTE**)&rgrsi, sizeof(RILSUBSCRIBERINFO), nUsed, &nAllocated, NETWK_ALLOC_NUMBER)) {
                hr = E_OUTOFMEMORY;
                goto Error;
            }
        }

        memset(&rgrsi[nUsed], 0x00, sizeof(RILSUBSCRIBERINFO));
        rgrsi[nUsed].cbSize = sizeof(RILSUBSCRIBERINFO);

        // Parse "<alpha>"
        if (ParseQuotedEncodedString(ENCODING_UCS2, szRsp, rgrsi[nUsed].wszDescription, rgrsi[nUsed].wszDescription + MAXLENGTH_DESCRIPTION)) {
            rgrsi[nUsed].dwParams |= RIL_PARAM_SI_DESCRIPTION;
        }

        // Parse ",<number>,<type>"
        if (!MatchStringBeginning(szRsp, ",", szRsp)                     ||
            !ParseString(szRsp, szAddress, MAXLENGTH_ADDRESS, szRsp)     ||
            !MatchStringBeginning(szRsp, ",", szRsp)                     ||
            !ParseUIntAndVerifyAbove(szRsp, FALSE, 0x100, nValue, szRsp) ||
            !StringToRILAddress(szAddress, (BYTE)nValue, rgrsi[nUsed].raAddress)) {
            goto Continue;
        }
        rgrsi[nUsed].dwParams |= RIL_PARAM_SI_ADDRESS;

        // Some radios are giving us empty +CNUM responses.
        // Don't return these (and don't include in multiline count).
        if (('\0' == szAddress[0]) &&
            (0 == (rgrsi[nUsed].dwParams & RIL_PARAM_SI_DESCRIPTION)))
        {
            goto Continue;
        }

        // This assignment is a heuristic that seems correct.
        rgrsi[nUsed].dwAddressId = dwCurrentAddressId++;
        rgrsi[nUsed].dwParams |= RIL_PARAM_SI_ADDRESSID;

        // Parse ","
        if (MatchStringBeginning(szRsp, ",", szRsp)) {
            // Parse "<speed>"
            if (!ParseUInt(szRsp, TRUE, nValue, szRsp)) {
                goto Continue;
            }
            for (i = 0; i < NUM_CONNSPEEDS; i++) {
                if (nValue == g_rgdwConnSpeeds[i]) {
                    rgrsi[nUsed].dwSpeed = i;
                    break;
                }
            }
            if (NUM_CONNSPEEDS == i) {
                // We couldn't match the response with anything
                rgrsi[nUsed].dwSpeed = RIL_SPEED_UNKNOWN;
            }
            rgrsi[nUsed].dwParams |= RIL_PARAM_SI_SPEED;

            // Parse ",<service>
            if (!MatchStringBeginning(szRsp, ",", szRsp) ||
                !ParseUInt(szRsp, TRUE, nValue, szRsp)) {
                goto Continue;
            }
            if (NUM_SERVICES > nValue) {
                rgrsi[nUsed].dwService = g_rgdwServices[nValue];
            } else {
                rgrsi[nUsed].dwService = RIL_SERVICE_UNKNOWN;
            }
            rgrsi[nUsed].dwParams |= RIL_PARAM_SI_SERVICE;

            // Parse ","
            if (MatchStringBeginning(szRsp, ",", szRsp)) {
                // Parse "<itc>"
                if (!ParseUIntAndVerifyAbove(szRsp, TRUE, 2, nValue, szRsp)) {
                    goto Continue;
                }
                rgrsi[nUsed].dwITC = (nValue ? RIL_ITC_UDI : RIL_ITC_31KHZ);
                rgrsi[nUsed].dwParams |= RIL_PARAM_SI_ITC;
            }
        }

        // Increment the array index
        nUsed++;

Continue:
        // Find "<postfix>"
        if (!FindRspPostfix(szRsp, szRsp)) {
            hr = E_FAIL;
            goto Error;
        }
    }

#ifdef TBD_DEBUG
    // For multi-line testing purposes, we can pretend that
    // we have an arbitrary number of lines.
    DWORD dwTotalSpoofedLines;
    if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SpoofMultipleLines"), &dwTotalSpoofedLines))
    {
        for ( ; dwCurrentAddressId < dwTotalSpoofedLines; dwCurrentAddressId++)
        {
            if (nUsed == nAllocated) {
                if (!AllocateOrReallocateStorage((BYTE**)&rgrsi, sizeof(RILSUBSCRIBERINFO), nUsed, &nAllocated, NETWK_ALLOC_NUMBER)) {
                    hr = E_OUTOFMEMORY;
                    goto Error;
                }
            }

            memset(&rgrsi[nUsed], 0x00, sizeof(RILSUBSCRIBERINFO));
            rgrsi[nUsed].cbSize = sizeof(RILSUBSCRIBERINFO);

            // This assignment is a heuristic that seems correct.
            rgrsi[nUsed].dwAddressId = dwCurrentAddressId++;
            rgrsi[nUsed].dwParams |= RIL_PARAM_SI_ADDRESSID;

            // Increment the array index
            nUsed++;
        }
    }
#endif
    pBlob = (void*)rgrsi;
    cbBlob = nUsed * sizeof(RILSUBSCRIBERINFO);

Error:
    if (FAILED(hr)) {
        FreeBlob(rgrsi);
    }
    return hr;
}

//
//
//
static HRESULT ParseGetSubscriberNumbersIntern(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetSubscriberNumbers);
    RILSUBSCRIBERINFO* rgrsi = NULL;
    HRESULT hr = S_OK;

    pBlob = NULL;
    cbBlob = 0;

    if(g_rsiused)
    {
        rgrsi = (RILSUBSCRIBERINFO*)AllocBlob(g_rsiused * sizeof(RILSUBSCRIBERINFO));
        if (!rgrsi) {
            hr = E_OUTOFMEMORY;
            goto Error;
        }
        memset(rgrsi, 0x00, g_rsiused * sizeof(RILSUBSCRIBERINFO));
        memcpy(rgrsi, &g_rsi, g_rsiused * sizeof(RILSUBSCRIBERINFO));

        pBlob = (void*)rgrsi;
        cbBlob = g_rsiused * sizeof(RILSUBSCRIBERINFO);
    }
    else
    {
        hr = E_FAIL;
    }
Error:
    return hr;
}


//
//
//
HRESULT RILDrv_GetSubscriberNumbers(DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetSubscriberNumbers);
    HRESULT hr = S_OK;
    BOOL bOK;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);

    if (!pHandle) {
        hr = E_FAIL;
        goto Error;
    }

    if (g_rsiused || ((g_dwModemType == MODEMTYPE_SIEMENS_MC45) || (g_dwModemType == MODEMTYPE_SIEMENS_MC46))) {
        bOK = QueueCmd(URC_PORT, pHandle, NULL, CMDOPT_NOOP, APIID_GETSUBSCRIBERNUMBERS, ParseGetSubscriberNumbersIntern, NULL, hr);
    } else {
        COM_PORT_TYPE iPort;

        iPort = COMMAND_PORT;
        if (IS_ADI)
            iPort = pHandle->GetDevice()->GetFreeAlternativeCmdPort(TRUE);
        bOK = QueueCmdWithRetry(iPort, pHandle, "AT+CNUM\r", CMDOPT_NONE, APIID_GETSUBSCRIBERNUMBERS, ParseGetSubscriberNumbers, NULL, hr, 8, 6000);
    }
    if (!bOK) {
        hr = E_FAIL;
        goto Error;
    }

Error:
    return hr;
}


//
//
//
static HRESULT ParseGetOperatorList(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetOperatorList);
    UINT nValue;
    UINT nUsed = 0;
    UINT nAllocated = 0;
    RILOPERATORINFO* rgroi = NULL;
    HRESULT hr = S_OK;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>+COPS: "
    if (!ParseRspPrefix(szRsp, szRsp) ||
        !MatchStringBeginning(szRsp, (pParam == (LPVOID)OPLIST_COPS)?"+COPS: ":"^SOPS: ", szRsp)) {
// If we don't get anything back, just return S_OK with pBlob=NULL and cbBlob=0.
//        hr = E_FAIL;
        goto Error;
    }

    // Parse "("
    while (MatchStringBeginning(szRsp, "(", szRsp)) {
        if (nUsed == nAllocated) {
            if (!AllocateOrReallocateStorage((BYTE**)&rgroi, sizeof(RILOPERATORINFO), nUsed, &nAllocated, NETWK_ALLOC_NUMBER)) {
                hr = E_OUTOFMEMORY;
                goto Error;
            }
        }

        memset(&rgroi[nUsed], 0x00, sizeof(RILOPERATORINFO));
        rgroi[nUsed].cbSize = sizeof(RILOPERATORINFO);
        rgroi[nUsed].ronNames.cbSize = sizeof(RILOPERATORNAMES);

        // Parse "<stat>"
        if (!ParseUInt(szRsp, TRUE, nValue, szRsp)) {
            goto Continue;
        }
        if (NUM_OPERSTATS > nValue) {
            rgroi[nUsed].dwStatus = g_rgdwOperStats[nValue];
        } else {
            rgroi[nUsed].dwStatus = RIL_OPSTATUS_UNKNOWN;
        }
        rgroi[nUsed].dwParams |= RIL_PARAM_OI_STATUS;

        if (pParam == (LPVOID)OPLIST_SOPS) {
            WCHAR wszOpName[MAXLENGTH_OPERATOR_LONG];
            UINT uiChars;

            // Parse "<eonsType>" (ignored)
            if (!MatchStringBeginning(szRsp, ",", szRsp)  || !ParseUInt(szRsp, TRUE, nValue, szRsp)) {
                goto Continue;
            }

            // Parse ",<long_name>"
            if (!MatchStringBeginning(szRsp, ",", szRsp)  ||
                !ParseUCS2String(szRsp, wszOpName, MAXLENGTH_OPERATOR_LONG, szRsp)) {
                goto Continue;
            }

            memset(rgroi[nUsed].ronNames.szLongName, 0, MAXLENGTH_OPERATOR_LONG);
            ConvertFromUnicode(ENCODING_ASCII, wszOpName, wcslen(wszOpName), rgroi[nUsed].ronNames.szLongName, MAXLENGTH_OPERATOR_LONG, uiChars);
        }
        else
        {
            // Parse ",<long_name>"
            if (!MatchStringBeginning(szRsp, ",", szRsp)  ||
                !ParseString(szRsp, rgroi[nUsed].ronNames.szLongName, MAXLENGTH_OPERATOR_LONG, szRsp)) {
                goto Continue;
            }
        }

        if (*rgroi[nUsed].ronNames.szLongName) {
            rgroi[nUsed].ronNames.dwParams |= RIL_PARAM_ON_LONGNAME;
            rgroi[nUsed].dwParams |= RIL_PARAM_OI_NAMES;
        }

        // Parse ",<short_name>"
        if (!MatchStringBeginning(szRsp, ",", szRsp)  ||
            !ParseString(szRsp, rgroi[nUsed].ronNames.szShortName, MAXLENGTH_OPERATOR_SHORT, szRsp)) {
            // Nothing
        }
        if (*rgroi[nUsed].ronNames.szShortName) {
            rgroi[nUsed].ronNames.dwParams |= RIL_PARAM_ON_SHORTNAME;
            rgroi[nUsed].dwParams |= RIL_PARAM_OI_NAMES;
        }

        // Parse ",<num_name>)"
        if (!MatchStringBeginning(szRsp, ",", szRsp)               ||
            !ParseString(szRsp, rgroi[nUsed].ronNames.szNumName, MAXLENGTH_OPERATOR_NUMERIC, szRsp) ||
            !MatchStringBeginning(szRsp, ")", szRsp)) {
            goto Continue;
        }
        if (*rgroi[nUsed].ronNames.szNumName) {
            rgroi[nUsed].ronNames.dwParams |= RIL_PARAM_ON_NUMNAME;
            rgroi[nUsed].dwParams |= RIL_PARAM_OI_NAMES;
        }

        // Fill in the long operator name, if we didn't get it
        GetLongOperatorName(&rgroi[nUsed].ronNames);

        // Increment the array index
        nUsed++;

Continue:
        // Parse ","
        if (!MatchStringAnywhere(szRsp, ",", szRsp)) {
            break;
        }
    }

    // NOTE: there may be more data here, but we don't care about it

    // Find "<postfix>"
    if (!FindRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    pBlob = (void*)rgroi;
    cbBlob = nUsed * sizeof(RILOPERATORINFO);

Error:
    if (FAILED(hr)) {
        FreeBlob(rgroi);
    }
    return hr;
}


//
//
//
HRESULT RILDrv_GetOperatorList(DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetOperatorList);
    HRESULT hr = S_OK;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle) {
        hr = E_FAIL;
        goto Error;
    }

    if (pHandle->GetDevice()->GetEons()->GetEONSState() == EONS_ENABLED)
    {
        // If we have native EONS support, we can take adventage of the enhance operator selection command.
        if (!QueueCmdWithRetry(COMMAND_PORT, pHandle, "AT^SOPS=?\r", CMDOPT_NONE, APIID_GETOPERATORLIST, ParseGetOperatorList, NULL, hr, 2, 7500, NULL, (LPVOID)OPLIST_SOPS)) {
            hr = E_FAIL;
            goto Error;
        }
    }
    else
    {
        if (!QueueCmdWithRetry(COMMAND_PORT, pHandle, "AT+COPS=?\r", CMDOPT_NONE, APIID_GETOPERATORLIST, ParseGetOperatorList, NULL, hr, 2, 7500, NULL, (LPVOID)OPLIST_COPS)) {
            hr = E_FAIL;
            goto Error;
        }
    }

Error:
    return hr;
}


DWORD g_dwNextFreeOperatorIndex = 1;
DWORD g_dwPreferredOperatorListStart=0, g_dwPreferredOperatorListEnd=0;

//
//
//
HRESULT ParseGetPreferredOperatorListSize(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetPreferredOperatorListSize);
    UINT nValue1, nValue2;
    HRESULT hr = S_OK;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>"
    if (!ParseRspPrefix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    // Parse "^SPLR: (1-8)<cr><lf>"
    if(!MatchStringBeginning(szRsp, "^SPLR: (", szRsp) ||
        !ParseUInt(szRsp, TRUE, nValue1, szRsp) ||
        !MatchStringBeginning(szRsp, "-", szRsp) ||
        !ParseUInt(szRsp, TRUE, nValue2, szRsp) ||
        !MatchStringBeginning(szRsp, ")", szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    // Find "<postfix>"
    if (!FindRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    g_dwPreferredOperatorListStart = nValue1;
    g_dwPreferredOperatorListEnd = nValue2;

Error:
    return hr;
}


//
//
//
static HRESULT ParseGetPreferredOperatorList(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetPreferredOperatorList);
    UINT nValue;
    UINT nUsed = 0;
    UINT nAllocated = 0;
    RILOPERATORINFO* rgroi = NULL;
    HRESULT hr = S_OK;
    char rgszTemp[20];
    UINT iBufferPos;
    BOOL fUseCPOL;
    LPCSTR szDummy;

    pBlob = NULL;
    cbBlob = 0;

    EnterCriticalSection(&g_PPLMNBufferSection);

    // Parse "<prefix>"
    if (!ParseRspPrefix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    g_iPPLMNBufferPos = PPLMN_BUFFER_NOT_FILLED;
    for (iBufferPos = 0; iBufferPos < MAX_PPLMN_BUFFER; iBufferPos++)
        g_PPLMNBuffer[iBufferPos] = 0;
    iBufferPos = 0;

    fUseCPOL = MatchStringBeginning(szRsp, "+CPOL: ", szDummy);

    // Parse "^SPLR: "
    while (MatchStringBeginning(szRsp, "^SPLR: ", szRsp) || MatchStringBeginning(szRsp, "+CPOL: ", szRsp)) {
        if (nUsed == nAllocated) {
            if (!AllocateOrReallocateStorage((BYTE**)&rgroi, sizeof(RILOPERATORINFO), nUsed, &nAllocated, NETWK_ALLOC_NUMBER)) {
                hr = E_OUTOFMEMORY;
                goto Error;
            }
        }

        memset(&rgroi[nUsed], 0x00, sizeof(RILOPERATORINFO));
        rgroi[nUsed].cbSize = sizeof(RILOPERATORINFO);
        rgroi[nUsed].ronNames.cbSize = sizeof(RILOPERATORNAMES);

        // Parse "<index>"
        if (!ParseUInt(szRsp, TRUE, nValue, szRsp)) {
            goto Continue;
        }
        rgroi[nUsed].dwIndex = nValue;
        rgroi[nUsed].dwParams |= RIL_PARAM_OI_INDEX;

        if (fUseCPOL) {
            // Parse ","
            if (!MatchStringBeginning(szRsp, ",", szRsp)) {
                goto Continue;
            }
            // Parse "<format>"
            if (!ParseUInt(szRsp, TRUE, nValue, szRsp)) {
                goto Continue;
            }
            // The parameter <format> is always equal 2 (numeric) so we don't need to parse it.
        }

        // Parse ","
        if (!MatchStringBeginning(szRsp, ",", szRsp)) {
            goto Continue;
        }
        // The name came in numeric format
        // Parse "<operator_name>"
        if (!ParseString(szRsp, rgszTemp, sizeof(rgszTemp), szRsp)) {
            goto Continue;
        }
        nValue = atoi(rgszTemp);
        (void)_snprintfz(rgroi[nUsed].ronNames.szNumName, MAXLENGTH_OPERATOR_NUMERIC, "%u", nValue);
        rgroi[nUsed].ronNames.dwParams |= RIL_PARAM_ON_NUMNAME;
        rgroi[nUsed].dwParams |= RIL_PARAM_OI_NAMES;

        if (rgroi[nUsed].dwIndex > iBufferPos) {
            iBufferPos = rgroi[nUsed].dwIndex;
        }
        if (rgroi[nUsed].dwIndex < MAX_PPLMN_BUFFER) {
            g_PPLMNBuffer[rgroi[nUsed].dwIndex] = nValue;
        }

        // Fill in the long operator name, if we didn't get it
        GetLongOperatorName(&rgroi[nUsed].ronNames);

        // Increment the array index
        nUsed++;

Continue:
        // Find "<postfix>"
        if (!FindRspPostfix(szRsp, szRsp)) {
            hr = E_FAIL;
            goto Error;
        }
    }

    if (iBufferPos < MAX_PPLMN_BUFFER) {
        g_iPPLMNBufferPos = iBufferPos;
    }

    pBlob = (void*)rgroi;
    cbBlob = nUsed * sizeof(RILOPERATORINFO);

Error:
    LeaveCriticalSection(&g_PPLMNBufferSection);
    if (FAILED(hr)) {
        FreeBlob(rgroi);
    }
    return hr;
}

//
//
//
static HRESULT ParseGetPreferredOperatorListFromStorage(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetPreferredOperatorListFromStorage);
    RILOPERATORINFO* rgroi = NULL;
    HRESULT hr = S_OK;
    UINT i, iPos;

    pBlob = NULL;
    cbBlob = 0;

    EnterCriticalSection(&g_PPLMNBufferSection);

    iPos = 0;
    for (i = 1; i < MAX_PPLMN_BUFFER; i++) {
        if (g_PPLMNBuffer[i] != 0)
            iPos += 1;
    }

    rgroi = (RILOPERATORINFO*)AllocBlob(iPos * sizeof(RILOPERATORINFO));
    if (rgroi == NULL) {
        hr = E_OUTOFMEMORY;
        goto Error;
    }

    iPos = 0;
    for (i = 1; i < MAX_PPLMN_BUFFER; i++) {
        if (g_PPLMNBuffer[i] != 0) {
            memset(&rgroi[iPos], 0x00, sizeof(RILOPERATORINFO));
            rgroi[iPos].cbSize = sizeof(RILOPERATORINFO);
            rgroi[iPos].ronNames.cbSize = sizeof(RILOPERATORNAMES);
            rgroi[iPos].dwIndex = i;
            rgroi[iPos].dwParams |= RIL_PARAM_OI_INDEX;
            (void)_snprintfz(rgroi[iPos].ronNames.szNumName, MAXLENGTH_OPERATOR_NUMERIC, "%u", g_PPLMNBuffer[i]);
            rgroi[iPos].ronNames.dwParams |= RIL_PARAM_ON_NUMNAME;
            rgroi[iPos].dwParams |= RIL_PARAM_OI_NAMES;
            GetLongOperatorName(&rgroi[iPos].ronNames);
            iPos++;
        }
    }

    pBlob = (void*)rgroi;
    cbBlob = iPos * sizeof(RILOPERATORINFO);

Error:
    LeaveCriticalSection(&g_PPLMNBufferSection);
    if (FAILED(hr)) {
        FreeBlob(rgroi);
    }
    return hr;
}

//
//
//
HRESULT RILDrv_GetPreferredOperatorList(DWORD dwParam, DWORD dwFormat)
{
    TBD_FUNCTION(RILDrv_GetPreferredOperatorList);
    UINT i;
    char szCmd[MAX_ATCMD_LEN];
    HRESULT hr = S_OK;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);

    if (!pHandle) {
        hr = E_FAIL;
        goto Error;
    }

    // Figure out the operator formats ID to use
    for (i = 0; i < NUM_OPERFORMATS; i++) {
        if (dwFormat == g_rgdwOperFormats[i]) {
            break;
        }
    }

    if (NUM_OPERFORMATS == i) {
        hr = E_INVALIDARG;
        goto Error;
    }

    if (g_dwModemType != MODEMTYPE_SIEMENS_MC55 && g_dwModemType != MODEMTYPE_SIEMENS_MC56) {
        if (g_dwPreferredOperatorListStart == 0) {
            if (!QueueCmdBlocking(COMMAND_PORT, pHandle, "AT^SPLR=?\r", CMDOPT_NONE, APIID_GETPREFERREDOPERATORLIST, ParseGetPreferredOperatorListSize, NULL, hr, 0, 0, 0)) {
                hr = E_FAIL;
                goto Error;
            }
        }
        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SPLR=%u,%u\r", g_dwPreferredOperatorListStart, g_dwPreferredOperatorListEnd);
    }
    else
        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CPOL?\r");

    if (!NEED_SPLW_WORKAROUND || g_iPPLMNBufferPos == PPLMN_BUFFER_NOT_FILLED) {
        EnterCriticalSection(&g_PPLMNBufferSection);
        g_dwNextFreeOperatorIndex = 1;
        g_iPPLMNBufferPos = PPLMN_BUFFER_NOT_FILLED;
        LeaveCriticalSection(&g_PPLMNBufferSection);

        if (!QueueCmdWithRetry(COMMAND_PORT, pHandle, szCmd, CMDOPT_NONE, APIID_GETPREFERREDOPERATORLIST, ParseGetPreferredOperatorList, NULL, hr, 2, 5000)) {
            hr = E_FAIL;
            goto Error;
        }
    }
    else {
        if (!QueueCmd(COMMAND_PORT, pHandle, NULL, CMDOPT_NOOP, APIID_GETPREFERREDOPERATORLIST, ParseGetPreferredOperatorListFromStorage, NULL, hr)) {
            hr = E_FAIL;
            goto Error;
        }
    }

Error:
    return hr;
}


//
//
//
HRESULT RILDrv_AddPreferredOperator(DWORD dwParam, DWORD dwIndex, const RILOPERATORNAMES* lpOperatorNames)
{
    TBD_FUNCTION(RILDrv_AddPreferredOperator);
    char szCmd[NETWK_CMDBUF_LENGTH];
    LPSTR szWalk = szCmd;
    HRESULT hr = S_OK;
    UINT i;
    UINT iIndex = 0;
    UINT iOperator = 0;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);

    EnterCriticalSection(&g_PPLMNBufferSection);

    if (!pHandle) {
        hr = E_FAIL;
        goto Error;
    }

    // Add the index (if supplied)
    if (RIL_PREFOPINDEX_FIRSTAVAILABLE == dwIndex) {
        if (g_iPPLMNBufferPos == PPLMN_BUFFER_NOT_FILLED)
        {
            iIndex = g_dwNextFreeOperatorIndex;
            g_dwNextFreeOperatorIndex++;
        }
        else
        {
            for (iIndex = 1; iIndex < MAX_PPLMN_BUFFER; iIndex++)
            {
                if (g_PPLMNBuffer[iIndex] == 0)
                    break;
            }
        }

        (void)_snprintfz(szWalk, NETWK_CMDBUF_LENGTH - (szWalk - szCmd), "AT^SPLW=%u,", iIndex);
    } else {
        iIndex = dwIndex;
        (void)_snprintfz(szWalk, NETWK_CMDBUF_LENGTH - (szWalk - szCmd), "AT^SPLW=%u,", dwIndex);
    }
    szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
    TBD_ASSERT(NULL != szWalk);

    if (lpOperatorNames->dwParams & RIL_PARAM_ON_NUMNAME) {
        // We have a numeric name -- use it
        (void)_snprintfz(szWalk, NETWK_CMDBUF_LENGTH - (szWalk - szCmd), "\"%s\"", lpOperatorNames->szNumName);
        iOperator = atoi(lpOperatorNames->szNumName);
        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    } else if (lpOperatorNames->dwParams & RIL_PARAM_ON_SHORTNAME) {
        // We have a short name -- use it
       (void)_snprintfz(szWalk, NETWK_CMDBUF_LENGTH - (szWalk - szCmd), "\"%s\"", lpOperatorNames->szNumName);
        iOperator = atoi(lpOperatorNames->szNumName);
        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    } else if (lpOperatorNames->dwParams & RIL_PARAM_ON_LONGNAME) {
        // We only have a long name
       (void)_snprintfz(szWalk, NETWK_CMDBUF_LENGTH - (szWalk - szCmd), "\"%s\"", lpOperatorNames->szNumName);
        iOperator = atoi(lpOperatorNames->szNumName);
        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);
    } else {
        // None of the names are specified
        hr = E_INVALIDARG;
        goto Error;
    }
    (void)strncpyz(szWalk, "\r", NETWK_CMDBUF_LENGTH - (szWalk - szCmd));  // NO_TYPO: 30

    if (iIndex < MAX_PPLMN_BUFFER && g_iPPLMNBufferPos != PPLMN_BUFFER_NOT_FILLED && iOperator != 0)
    {
        // Since the Siemens modules don't allow the same operator twice in the list,
        // we now have to recheck the whole command:

        // Step 1: Is the same operator in the list before out position? If yes, we just do nothing.
        for (i = 1; i < iIndex; i++)
        {
            if (g_PPLMNBuffer[i] == iOperator)
                break;
        }
        if (i < iIndex)
        {
            (void)strncpyz(szCmd, "AT\r", NETWK_CMDBUF_LENGTH);
        }
        else
        {
            // Step 2: Is the same operator in the list behind our position? If so, we have to delete it first.

            for (i = iIndex+1; i < MAX_PPLMN_BUFFER; i++)
            {
                if (g_PPLMNBuffer[i] == iOperator)
                    break;
            }

            if (i < MAX_PPLMN_BUFFER)
            {
                (void)_snprintfz(szCmd, NETWK_CMDBUF_LENGTH, "AT^SPLW=%u;^SPLW=%u,%u\r", i, iIndex, iOperator);
                g_PPLMNBuffer[i] = 0;
            }
            if (iIndex < MAX_PPLMN_BUFFER)
            {
                g_PPLMNBuffer[iIndex] = iOperator;
            }
        }
    }

    if (!NEED_SPLW_WORKAROUND || g_iPPLMNBufferPos == PPLMN_BUFFER_NOT_FILLED) {
        if (!QueueCmd(COMMAND_PORT, pHandle, szCmd, CMDOPT_NONE, APIID_ADDPREFERREDOPERATOR, NULL, NULL, hr)) {
            hr = E_FAIL;
            goto Error;
        }
    }
    else {
        UINT iIndexMax, iIndexNum;

        // The MC75 preferred operator list is a little bit tricky. If we only write to the end of the list, we
        // can use the original command. In any other case the best solution ist to erase the list completly and
        // write it new in the MC75-style.
        iIndexNum = 0;
        iIndexMax = 0;
        for (i = 1; i <= MAX_PPLMN_BUFFER; i++) {
            if (g_PPLMNBuffer[i] != 0) {
                iIndexNum ++;
                iIndexMax = i;
            }
        }
        if (iIndexNum == iIndexMax && strstr(";^", szCmd) == NULL) {
            char szCmd2[NETWK_CMDBUF_LENGTH];

            // We just add an operator to the end of the list, so can use the original command, but first
            // we have to delete the current entry, otherwise we might get a "SIM full" error in case there
            // in no space left in the list. If this is already the last entry of the list, we will get an
            // error message,which can be ignored.
            (void)_snprintfz(szCmd2, NETWK_CMDBUF_LENGTH, "AT^SPLW=%u\r", iIndex);
            QueueInternalCmd(COMMAND_PORT, pHandle->GetDevice(), szCmd2, CMDOPT_NONE, APIID_REMOVEPREFERREDOPERATOR, 0, 0, 0);

            if (!QueueCmd(COMMAND_PORT, pHandle, szCmd, CMDOPT_NONE, APIID_ADDPREFERREDOPERATOR, NULL, NULL, hr)) {
                hr = E_FAIL;
                goto Error;
            }
        }
        else {
            // First we delete the whole list. The last AT^SPLW command may fail in case we add an operator
            // rather than modify an existing one. The resulting "+CME ERROR" is of no consequence, so we
            // do not check the result of the command.
            for (i = 1; i <= MAX_PPLMN_BUFFER; i++) {
                if (g_PPLMNBuffer[i] != 0) {
                    QueueInternalCmd(COMMAND_PORT, pHandle->GetDevice(), "AT^SPLW=1\r", CMDOPT_NONE, APIID_REMOVEPREFERREDOPERATOR, 0, 0, 0);
                }
            }
            if (strstr(";^", szCmd) != NULL) {
                QueueInternalCmd(COMMAND_PORT, pHandle->GetDevice(), "AT^SPLW=1\r", CMDOPT_NONE, APIID_REMOVEPREFERREDOPERATOR, 0, 0, 0);
            }

            // We now write the new list in the MC75-style, which means, there are no empty places within the
            // list allowed.
            iIndex = 1;
            for (i = 1; i <= MAX_PPLMN_BUFFER; i++) {
                if (g_PPLMNBuffer[i] != 0) {
                    (void)_snprintfz(szCmd, NETWK_CMDBUF_LENGTH, "AT^SPLW=%u,\"%u\"\r", iIndex, g_PPLMNBuffer[i]);
                    QueueInternalCmd(COMMAND_PORT, pHandle->GetDevice(), szCmd, CMDOPT_NONE, APIID_ADDPREFERREDOPERATOR, 0, 0, 0);
                    iIndex++;
                }
            }
            if (!QueueCmd(COMMAND_PORT, pHandle, NULL, CMDOPT_NOOP, APIID_ADDPREFERREDOPERATOR, NULL, NULL, hr)) {
                hr = E_FAIL;
                goto Error;
            }
        }
    }

Error:
    LeaveCriticalSection(&g_PPLMNBufferSection);
    return hr;
}


//
//
//
HRESULT RILDrv_RemovePreferredOperator(DWORD dwParam, DWORD dwIndex)
{
    TBD_FUNCTION(RILDrv_RemovePreferredOperator);
    char szCmd[MAX_ATCMD_LEN];
    HRESULT hr = S_OK;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    DWORD dwIndexVirt;

    EnterCriticalSection(&g_PPLMNBufferSection);

    if (!pHandle) {
        hr = E_FAIL;
        goto Error;
    }

    dwIndexVirt = dwIndex;
    if (NEED_SPLW_WORKAROUND && g_iPPLMNBufferPos != PPLMN_BUFFER_NOT_FILLED) {
        UINT i;

        dwIndexVirt = 0;
        for (i = 1; i <= dwIndex; i++) {
            if (g_PPLMNBuffer[i] > 0)
                dwIndexVirt += 1;
        }
    }

    // Add the index 
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SPLW=%u\r", dwIndexVirt);

    if (dwIndex < MAX_PPLMN_BUFFER) {
        if (NEED_SPLW_WORKAROUND && g_PPLMNBuffer[dwIndex] == 0) {
            if (!QueueCmd(COMMAND_PORT, pHandle, NULL, CMDOPT_NOOP, APIID_REMOVEPREFERREDOPERATOR, NULL, NULL, hr)) {
                hr = E_FAIL;
            }
            goto Error;
        }
        g_PPLMNBuffer[dwIndex] = 0;
    }
    if (!QueueCmd(COMMAND_PORT, pHandle, szCmd, CMDOPT_NONE, APIID_REMOVEPREFERREDOPERATOR, NULL, NULL, hr)) {
        hr = E_FAIL;
        goto Error;
    }

Error:
    LeaveCriticalSection(&g_PPLMNBufferSection);
    return hr;
}


//
//
//
HRESULT ParseGetCurrentOperator(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetCurrentOperator);
    UINT nValue;
    UINT nFormat;
    RILOPERATORNAMES* pron = NULL;
    HRESULT hr = S_OK;

    pBlob = NULL;
    cbBlob = 0;

    pron = (RILOPERATORNAMES*)AllocBlob(sizeof(RILOPERATORNAMES));
    if (!pron) {
        hr = E_OUTOFMEMORY;
        goto Error;
    }
    memset(pron, 0x00, sizeof(RILOPERATORNAMES));
    pron->cbSize = sizeof(RILOPERATORNAMES);

    // Parse "<prefix>+COPS: <mode>"
    if (!ParseRspPrefix(szRsp, szRsp)                  ||
        !MatchStringBeginning(szRsp, "+COPS: ", szRsp) ||
        !ParseUInt(szRsp, TRUE, nValue, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    g_iLastCOPS = nValue;

    // See if we have the operator info
    if (!MatchStringBeginning(szRsp, ",", szRsp)) {
        // We're not currently registered with an operator
        hr = RIL_E_OPFMTUNAVAILABLE;
        goto Error;
    }

    // Parse "<format>"
    if (!ParseUInt(szRsp, TRUE, nFormat, szRsp) ||
        !MatchStringBeginning(szRsp, ",", szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (!nFormat) {
        // The name came in long format
        // Parse "<operator_name>"
        if(!ParseString(szRsp, pron->szLongName, MAXLENGTH_OPERATOR_LONG, szRsp)) {
            hr = E_FAIL;
            goto Error;
        }
        if (*pron->szLongName) {
            pron->dwParams |= RIL_PARAM_ON_LONGNAME;
        }
    } else if (1 == nFormat) {
        // The name came in short format
        // Parse "<operator_name>"
        if(!ParseString(szRsp, pron->szShortName, MAXLENGTH_OPERATOR_SHORT, szRsp)) {
            hr = E_FAIL;
            goto Error;
        }
        if (*pron->szShortName) {
            pron->dwParams |= RIL_PARAM_ON_SHORTNAME;
        }
    } else if (2 == nFormat) {
        // The name came in numeric format
        // Parse "<operator_name>"
        if (*szRsp=='\"') szRsp++;    // Ignore " characters around operator number

        if (!ParseUInt(szRsp, TRUE, nValue, szRsp)) {
            hr = E_FAIL;
            goto Error;
        }

        if (*szRsp=='\"') szRsp++;    // Ignore " characters around operator number

        (void)_snprintfz(pron->szNumName, MAXLENGTH_OPERATOR_NUMERIC, "%u", nValue);
        pron->dwParams |= RIL_PARAM_ON_NUMNAME;
    } else {
        // Unknown name format
        hr = E_FAIL;
        goto Error;
    }

    // Parse "<postfix>"
    if (!ParseRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    // Fill in the long operator name, if we didn't get it
    GetLongOperatorName(pron);

    pBlob = (void*)pron;
    cbBlob = sizeof(RILOPERATORNAMES);

Error:
    if (FAILED(hr)) {
        FreeBlob(pron);
    }
    return hr;
}


//
//
//
HRESULT RILDrv_GetCurrentOperator(DWORD dwParam, DWORD dwFormat)
{
    TBD_FUNCTION(RILDrv_GetCurrentOperator);
    char szCmd[MAX_ATCMD_LEN];
    UINT i;
    HRESULT hr = S_OK;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    LPCSTR szEonsLongName;
    LPCSTR szEonsShortName;
    BOOL fEonsFound = FALSE;

    if (!pHandle) {
        hr = E_FAIL;
        goto Error;
    }
#ifdef AUXCOM_PORT
    // Problem of Microsoft MMI: some applications (eg. the radiotest.exe) tend to test the
    // provider name, while the module is still searching.
    // Workaround: we give the module a little bit time (5s) toregister. Since
    // the incomming +CREG URC will come on the other multiplexer channel, this
    // waiting period will not block.
    i = 0;

    while (i < 50 && g_dwRegStatus==RIL_REGSTAT_ATTEMPTING) {
        Sleep(100);
        i++;
    }
    i = 0;
#endif
    // Figure out the operator formats ID to use
    for (i = 0; i < NUM_OPERFORMATS; i++) {
        if (dwFormat == g_rgdwOperFormats[i]) {
            break;
        }
    }
    if (NUM_OPERFORMATS == i) {
        hr = E_INVALIDARG;
        goto Error;
    }

    if (dwFormat != RIL_OPFORMAT_NUM) {
        fEonsFound = pHandle->GetDevice()->GetEons()->GetOperatorInfo(pHandle, &szEonsLongName, &szEonsShortName);
        if (fEonsFound == TRUE) {
            RILOPERATORNAMES    ron;
            CNotificationData*  pnd = NULL;
            memset(&ron, 0x00, sizeof(RILOPERATORNAMES));
            ron.cbSize = sizeof(RILOPERATORNAMES);
            if (szEonsLongName && (dwFormat == RIL_OPFORMAT_LONG)) {
                ron.dwParams |= RIL_PARAM_ON_LONGNAME;
                strncpy(ron.szLongName, szEonsLongName, MAXLENGTH_OPERATOR_LONG);
                if (szEonsShortName && (dwFormat == RIL_OPFORMAT_SHORT)) {
                    ron.dwParams |= RIL_PARAM_ON_SHORTNAME;
                    strncpy(ron.szShortName, szEonsShortName, MAXLENGTH_OPERATOR_SHORT);
                } else {
                    fEonsFound = FALSE;
                }
            } else {
                fEonsFound = FALSE;
            }
            if (fEonsFound == TRUE) {
                pnd = new CNotificationData;
                if (!pnd) {
                    hr = E_OUTOFMEMORY;
                    goto Error;
                }
                if (!pnd->InitFromRealBlob(RIL_NOTIFY_REGSTATUSCHANGED, &ron, ron.cbSize)) {
                    hr = E_OUTOFMEMORY;
                    delete pnd;
                    goto Error;
                }
                pHandle->GetDevice()->BroadcastNotification(pnd);
#ifdef RIL_USE_CSQ_NOTIFICATIONS
                if (g_bCINDIsActive)
                {
                    CreateThread(NULL, 0, ReSendSignalThreadProc, (LPVOID)pHandle->GetDevice(), 0, 0);
                }
#endif
            }
        }
    }

    if (fEonsFound != TRUE) {
        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=3,%u;+COPS?\r", i);
        Sleep(500);
        if (!QueueCmd(COMMAND_PORT, pHandle, szCmd, CMDOPT_NONE, APIID_GETCURRENTOPERATOR, ParseGetCurrentOperator, NULL, hr)) {
            hr = E_FAIL;
            goto Error;
        }
    }

Error:
    return hr;
}

//
//
//
HRESULT RILDrv_RegisterOnNetwork(DWORD dwParam, DWORD dwMode, const RILOPERATORNAMES* lpOperatorNames)
{
    TBD_FUNCTION(RILDrv_RegisterOnNetwork);
    HRESULT hr = S_OK;
    char szCmd[NETWK_CMDBUF_LENGTH];
    LPSTR szWalk = szCmd;
    UINT i;
    BOOL bUseQuotes=TRUE;
    BOOL bOmitCOPS = FALSE;
    const char *pszName;

    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle) {
        hr = E_FAIL;
        goto Error;
    }

    // Figure out the mode ID to use
    for (i = 0; i < NUM_OPSELMODES; i++) {
        if (dwMode == g_rgdwOperSelModes[i]) {
            break;
        }
    }
    if (NUM_OPSELMODES == i) {
        hr = E_INVALIDARG;
        goto Error;
    }

    // Problem: if we change between two roaming networks, there change will be indicated by a +CREG: 5 URC with
    // new location information. Since the last +CREG-URC was also a +CREG: 5 URC, this would normally not be
    // reported as a regitration state change.
    // Workaround: if we change manually the network, we treat the next +CREG-URC always as an registration state
    // change.
    g_fReportLocationUpdateAsRegistrationState = TRUE;

    hr = S_OK;
    if ((g_bRadioOff || (g_dwReadyState & (RIL_READYSTATE_SIM|RIL_READYSTATE_UNLOCKED|RIL_READYSTATE_SMS)) != (RIL_READYSTATE_SIM|RIL_READYSTATE_UNLOCKED|RIL_READYSTATE_SMS)) && (i ==0 || ( lpOperatorNames==NULL ? FALSE : (lpOperatorNames->dwParams & RIL_PARAM_ON_NUMNAME))))
    {
        RILRetailTrace((TEXT("RilDrv: AT+COPS=%u scheduled for end of post-PIN initialization\r\n"), i));
        g_iSetCOPSinInit = i;
        if (i != 0)
        {
            (void)strncpyz(g_szSetCOPSinInitOperator, lpOperatorNames->szNumName, MAXLENGTH_OPERATOR_NUMERIC);
            g_szSetCOPSinInitOperator[MAXLENGTH_OPERATOR_NUMERIC] = 0;
        }
        bOmitCOPS = TRUE;
    }
    else
    {
        // Query the current +COPS state for further use. The result will be stored in g_iLastCOPS.
        QueueInternalCmdBlocking(COMMAND_PORT, pHandle->GetDevice(), "AT+COPS?\r", CMDOPT_NONE, APIID_GETCURRENTOPERATOR, 0, 0, 0, ParseGetCurrentOperator);

        if ((g_dwGPRSRegStatus == RIL_REGSTAT_HOME || g_dwGPRSRegStatus == RIL_REGSTAT_ROAMING) && (g_iLastCOPS != i || i != 0)) {
            bool fGPRSAutoDetach;

            // If we are attached to GPRS, we should detach manually, if configured.
            if (GetRegistryBoolean(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("GPRSAutoDetach"), &fGPRSAutoDetach) && fGPRSAutoDetach) {
                QueueInternalCmd(pHandle->GetDevice()->GetComDevice(DATA_PORT)->FDataMode()?COMMAND_PORT:DATA_PORT, pHandle->GetDevice(), "AT+CGATT=0\r", CMDOPT_IGNORERSP, APIID_DEVSPECIFIC, 0, 0, 0);
            }
        }

        // Special problem with MC75: if the module is already in auto registration mode it should be avoided
        // to user AT+COPS=0 again.
        if (g_iLastCOPS == i && i == 0)
            bOmitCOPS = TRUE;

        if (g_iLastCOPS != i || i == 1) {
            g_iLastCOPS = i;
        }

        // Add the mode
        (void)_snprintfz(szWalk, NETWK_CMDBUF_LENGTH - (szWalk - szCmd), "AT+COPS=%u", i);

        szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
        TBD_ASSERT(NULL != szWalk);

        if ( (lpOperatorNames!=NULL) && (lpOperatorNames->dwParams!=0) )
        {
            if (lpOperatorNames->dwParams & RIL_PARAM_ON_NUMNAME)
            {
                // numeric format
                (void)strncpyz(szWalk, ",2", NETWK_CMDBUF_LENGTH - (szWalk - szCmd));  // NO_TYPO: 30
                pszName = lpOperatorNames->szNumName;
                bUseQuotes=FALSE;
            }
            else if (lpOperatorNames->dwParams & RIL_PARAM_ON_SHORTNAME)
            {
                // short name format
                (void)strncpyz(szWalk, ",1", NETWK_CMDBUF_LENGTH - (szWalk - szCmd));  // NO_TYPO: 30
                pszName = lpOperatorNames->szShortName;
            }
            else if (lpOperatorNames->dwParams & RIL_PARAM_ON_LONGNAME)
            {
                // long name format
                (void)strncpyz(szWalk, ",0", NETWK_CMDBUF_LENGTH - (szWalk - szCmd));  // NO_TYPO: 30
                pszName = lpOperatorNames->szLongName;
            }
            else
            {
                // None of the names are specified
                hr = E_INVALIDARG;
                goto Error;
            }

            szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
            TBD_ASSERT(NULL != szWalk);

            if ((dwMode!=RIL_OPSELMODE_AUTOMATIC) && (pszName[0]!='\0'))
            {
                if (bUseQuotes)
                {
                    (void)_snprintfz(szWalk, NETWK_CMDBUF_LENGTH - (szWalk - szCmd), ",\"%s\"", pszName);
                }
                else
                {
                    (void)_snprintfz(szWalk, NETWK_CMDBUF_LENGTH - (szWalk - szCmd), ",%s", pszName);
                }

                szWalk = strchr(szWalk, '\0');  // NO_TYPO: 27
                TBD_ASSERT(NULL != szWalk);
            }
        }

        (void)strncpyz(szWalk, "\r", NETWK_CMDBUF_LENGTH - (szWalk - szCmd));  // NO_TYPO: 30
    }

    if (bOmitCOPS) {
        // If the AT-command can be omitted (see comments above), we only send a no-operation command.
        if (!QueueCmd(URC_PORT, pHandle, NULL, CMDOPT_NOOP, APIID_REGISTERONNETWORK, NULL, NULL, hr)) {
            hr = E_FAIL;
            goto Error;
        }
    }
    else {
        if (!QueueCmd(COMMAND_PORT, pHandle, szCmd, CMDOPT_NONE, APIID_REGISTERONNETWORK, NULL, NULL, hr)) {
            hr = E_FAIL;
            goto Error;
        }
    }

Error:
    return hr;
}


//
//
//
HRESULT RILDrv_UnregisterFromNetwork(DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_UnregisterFromNetwork);
    HRESULT hr = S_OK;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle) {
        hr = E_FAIL;
        goto Error;
    }

    g_iLastCOPS = 2;

    if (g_bRadioOff) {
        RILRetailTrace((TEXT("RilDrv: AT+COPS=2 scheduled for post-PIN initialization\r\n")));
        g_iSetCOPSinInit = 2;
        if (!QueueCmd(URC_PORT, pHandle, NULL, CMDOPT_NOOP, APIID_UNREGISTERFROMNETWORK, NULL, NULL, hr)) {
            hr = E_FAIL;
            goto Error;
        }
    }
    else {
        if (!QueueCmd(COMMAND_PORT, pHandle, "AT+COPS=2\r", CMDOPT_NONE, APIID_UNREGISTERFROMNETWORK, NULL, NULL, hr)) {
            hr = E_FAIL;
            goto Error;
        }
    }

Error:
    return hr;
}


//
//
//
HRESULT ParseGetRegistrationStatus(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetRegistrationStatus);
    UINT nValue;
    DWORD* pdwRegStatus = NULL;
    HRESULT hr = S_OK;
    UINT dwLAC, dwCI;

    pBlob = NULL;
    cbBlob = 0;

    pdwRegStatus = (DWORD*)AllocBlob(sizeof(DWORD));
    if (!pdwRegStatus) {
        hr = E_OUTOFMEMORY;
        goto Error;
    }
    memset(pdwRegStatus, 0x00, sizeof(DWORD));

    // Parse "<prefix>+CREG: <mode>,<status>,...<postfix>"
    if (!ParseRspPrefix(szRsp, szRsp)                  ||
        !MatchStringBeginning(szRsp, "+CREG: ", szRsp) ||
        !ParseUInt(szRsp, TRUE, nValue, szRsp)         ||
        !MatchStringBeginning(szRsp, ",", szRsp)       ||
        !ParseUInt(szRsp, TRUE, nValue, szRsp))         {
        hr = E_FAIL;
        goto Error;
    }

    dwLAC = 0;
    dwCI = 0;
    // There may be additional location information.
    if (MatchStringBeginning(szRsp, ",\"", szRsp))
    {
        ParseHexUInt(szRsp, TRUE, dwLAC, szRsp);
        MatchStringBeginning(szRsp, "\",\"", szRsp);
        ParseHexUInt(szRsp, TRUE, dwCI, szRsp);
        MatchStringBeginning(szRsp, "\"", szRsp);
    }

    if (!ParseRspPostfix(szRsp, szRsp))
    {
        hr = E_FAIL;
        goto Error;
    }

    if (NUM_REGSTATS > nValue) {
        *pdwRegStatus = g_rgdwRegStats[nValue];
    } else {
        *pdwRegStatus = RIL_REGSTAT_UNKNOWN;
    }

    g_dwRegStatus = *pdwRegStatus;


#ifndef RIL_NO_CREG_LOCATION_UPDATES
    if (pParam != NULL && dwLAC!=0 && dwCI!=0 && (nValue == 1 || nValue == 5))
    {
        CRilHandle *pDevice;
        CNotificationData *pnd = NULL;
        RILLOCATIONINFO sLI;

        pDevice = (CRilHandle *)pParam;

        sLI.cbSize = sizeof(RILLOCATIONINFO);
        sLI.dwLocationAreaCode = dwLAC;
        sLI.dwCellID = dwCI;

        pnd = new CNotificationData;
        if (pnd)
        {
            if (!pnd->InitFromRealBlob(RIL_NOTIFY_LOCATIONUPDATE, &sLI, sizeof(RILLOCATIONINFO)))
            {
                delete pnd;
                pnd = NULL;
            }
            pDevice->BroadcastNotification(pnd);
        }
    }
#endif

    pBlob = (void*)pdwRegStatus;
    cbBlob = sizeof(DWORD);

Error:
    if (FAILED(hr)) {
        FreeBlob(pdwRegStatus);
    }
    return hr;
}


//
//
//
HRESULT RILDrv_GetRegistrationStatus(DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetRegistrationStatus);
    HRESULT hr = S_OK;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle) {
        hr = E_FAIL;
        goto Error;
    }

    if (!QueueCmd(URC_PORT, pHandle, "AT+CREG?\r", CMDOPT_NONE, APIID_GETREGISTRATIONSTATUS, ParseGetRegistrationStatus,
                  NULL, hr)) {
        hr = E_FAIL;
        goto Error;
    }

Error:
    return hr;
}

#ifndef X86_EMUL
//
// Comparison routine used for quicksort below
//
static int _cdecl QSCompareMCCNames(const void* pElem1, const void* pElem2)
{
    int nRet;
    const RILOPERATORNAMES* pron1 = (RILOPERATORNAMES*)pElem1;
    const RILOPERATORNAMES* pron2 = (RILOPERATORNAMES*)pElem2;

    TBD_ASSERT((0 != pron1) &&
               ((pron1->dwParams & RIL_PARAM_ON_LONGNAME|RIL_PARAM_ON_COUNTRY_CODE|RIL_PARAM_ON_NUMNAME) == (RIL_PARAM_ON_LONGNAME|RIL_PARAM_ON_COUNTRY_CODE|RIL_PARAM_ON_NUMNAME)) &&
               (0 != pron1->szCountryCode) &&
               (0 != pron1->szLongName) &&
               (0 != pron1->szNumName));

    TBD_ASSERT((0 != pron2) &&
               ((pron2->dwParams & RIL_PARAM_ON_LONGNAME|RIL_PARAM_ON_COUNTRY_CODE|RIL_PARAM_ON_NUMNAME) == (RIL_PARAM_ON_LONGNAME|RIL_PARAM_ON_COUNTRY_CODE|RIL_PARAM_ON_NUMNAME)) &&
               (0 != pron2->szCountryCode) &&
               (0 != pron2->szLongName) &&
               (0 != pron2->szNumName));


    BOOL fUnk1 = (0 == strcmp(pron1->szCountryCode, UNKNOWN_COUNTRY_CODE));
    BOOL fUnk2 = (0 == strcmp(pron2->szCountryCode, UNKNOWN_COUNTRY_CODE));
    if (!fUnk1 && fUnk2) {
        nRet = -1;
    } else if (fUnk1 && !fUnk2) {
        nRet = 1;
    } else {
        int iMCCCompare = CompareString(LOCALE_USER_DEFAULT, 0, WideString(pron1->szCountryCode), -1, WideString(pron2->szCountryCode), -1);
        if (CSTR_LESS_THAN == iMCCCompare) {
            nRet = -1;
        } else if (CSTR_GREATER_THAN == iMCCCompare) {
            nRet = 1;
        } else {
            TBD_ASSERT(CSTR_EQUAL == iMCCCompare);
            int iLongNameCompare = CompareString(LOCALE_USER_DEFAULT, 0, WideString(pron1->szLongName), -1, WideString(pron2->szLongName), -1);
            if (CSTR_LESS_THAN == iLongNameCompare) {
                nRet = -1;
            } else if (CSTR_GREATER_THAN == iLongNameCompare) {
                nRet = 1;
            } else {
                TBD_ASSERT(CSTR_EQUAL == iLongNameCompare);
                const char* szNum1 = (strlen(pron1->szNumName) > MCC_LEN) ? ((pron1->szNumName)+MCC_LEN) : "";
                const char* szNum2 = (strlen(pron2->szNumName) > MCC_LEN) ? ((pron2->szNumName)+MCC_LEN) : "";
                int iNumNameCompare = CompareString(LOCALE_USER_DEFAULT, 0, WideString(szNum1), -1, WideString(szNum2), -1);
                if (CSTR_LESS_THAN == iNumNameCompare) {
                    nRet = -1;
                } else if (CSTR_GREATER_THAN == iNumNameCompare) {
                    nRet = 1;
                } else {
                    TBD_ASSERT(CSTR_EQUAL == iNumNameCompare);
                    nRet = 0;
                }
            }
        }
    }

    return nRet;
}


//
//
//
static HRESULT ParseGetAllOperatorsList(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    TBD_FUNCTION(ParseGetAllOperatorsList);
    HRESULT hr = S_OK;
    RILOPERATORNAMES* pron = NULL;
    int i;
    const UINT uiBlobSize = NUM_OPERATORNAMES * sizeof(RILOPERATORNAMES);

    //ok, copy over the list of all known networks...
    pron = (RILOPERATORNAMES*)AllocBlob(uiBlobSize);
    if (!pron) {
        hr = E_OUTOFMEMORY;
        goto Error;
    }

    for(i = 0; i < NUM_OPERATORNAMES; i++) {
        memset(&(pron[i]), 0x00, sizeof(pron[i]));
        pron[i].cbSize = sizeof(pron[i]);
        //numeric name
        _itoa(g_rgonmOperatorNames[i].nNumericName, pron[i].szNumName, 10);
        //long name
        strncpyz(pron[i].szLongName, g_rgonmOperatorNames[i].szLongName, MAXLENGTH_OPERATOR_LONG);
        //MCC ISO country code
        strncpyz(pron[i].szCountryCode, g_rgonmOperatorNames[i].szCountryCode, MAXLENGTH_OPERATOR_COUNTRY_CODE);
        //set valid params
        pron[i].dwParams = RIL_PARAM_ON_LONGNAME|RIL_PARAM_ON_NUMNAME|RIL_PARAM_ON_COUNTRY_CODE;
    }

    //now sort by MCC ISO code
    qsort(pron, NUM_OPERATORNAMES, sizeof(pron[0]), QSCompareMCCNames);

    pBlob = (void*)pron;
    cbBlob = uiBlobSize;

Error:
    if (FAILED(hr)) {
        FreeBlob(pron);
    }
    return hr;
}

HRESULT RILDrv_GetAllOperatorsList(DWORD dwParam)
{
    TBD_FUNCTION(RILDrv_GetRegistrationStatus);
    HRESULT hr = S_OK;

    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle) {
        hr = E_FAIL;
        goto Error;
    }

    if (!QueueCmd(COMMAND_PORT, pHandle, NULL, CMDOPT_NOOP, APIID_GETALLOPERATORSLIST, ParseGetAllOperatorsList, NULL, hr)) {
        hr = E_FAIL;
        goto Error;
    }

Error:
    return hr;
}
#endif

